T08 · Insecure Dependencies
Error
- Location
- scripts/detect.py:27
- Finding
- Unverified Remote Model Retrieval and Loading<![CDATA[ ## Vulnerability Details **File Location**: `scripts/detect.py:27-29, 33-58, 80-86` **Vulnerability Type**: Unverified third-party model download and unsafe supply-chain trust **Risk Level**: High ### Vulnerable Code ```python MODEL_DOWNLOAD_URLS = [ ("head-yolov8m.pt", "https://github.com/Abcfsa/YOLOv8_head_detector/raw/main/medium.pt"), ("head-yolov8s.pt", "https://github.com/Abcfsa/YOLOv8_head_detector/raw/main/nano.pt"), ] def _download_model(save_dir: str, max_retries: int = 3) -> bool: """Download model weights from GitHub and retry automatically.""" import urllib.request import time os.makedirs(save_dir, exist_ok=True) for filename, url in MODEL_DOWNLOAD_URLS: target = os.path.join(save_dir, filename) if os.path.exists(target): return True for attempt in range(1, max_retries + 1): try: urllib.request.urlretrieve(url, target) return True except Exception as e: if os.path.exists(target): os.remove(target) if attempt < max_retries: time.sleep(attempt * 5) return False ``` The downloaded file is subsequently passed directly to Ultralytics: ```python models_dir = os.path.join(SKILL_DIR, "models") if _download_model(models_dir): for path in MODEL_PATHS: if os.path.exists(path): return YOLO(path), False ``` ### Technical Analysis When no local model is available, the Skill downloads model artifacts from URLs referencing the mutable `main` branch of a third-party GitHub repository. The downloaded files are accepted solely based on successful transfer and existence on disk. The implementation does not perform any of the following controls: - Verification against a pinned SHA-256 digest - Signature or trusted-manifest verification - Pinning to an immutable release or commit - Validation of the downloaded artifact format - Enf ...[truncated 2090 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Pin each model to an immutable release artifact or repository commit rather than the mutable `main` branch. 2. Publish an independently reviewed SHA-256 digest with the Skill and verify it before loading: ```python import hashlib EXPECTED_SHA256 = { "head-yolov8m.pt": "<reviewed-sha256>", "head-yolov8s.pt": "<reviewed-sha256>", } def verify_sha256(path, expected): digest = hashlib.sha256() with open(path, "rb") as model_file: for block in iter(lambda: model_file.read(1024 * 1024), b""): digest.update(block) return digest.hexdigest() == expected ``` 3. Download to a uniquely created temporary file in the destination directory. 4. Enforce an expected maximum and minimum artifact size during transfer. 5. Reject redirects whose final scheme or hostname is not explicitly approved. 6. Validate the hash and artifact structure before atomically renaming the temporary file to the trusted model path. 7. Delete the temporary artifact on every validation or loading failure. 8. Prefer a non-executable tensor serialization format, such as `safetensors`, where the model stack supports it. 9. Consider packaging the reviewed model with the Skill or requiring explicit administrator installation instead of automatic retrieval. ]]>
