T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/media_gen_client.py:79
- Finding
- Unvalidated Server-Provided URL Enables Arbitrary Resource Retrieval## Vulnerability Details **File Location**: `scripts/media_gen_client.py:79-101`, with the untrusted download URL consumed at `scripts/media_gen_client.py:265-270` **Vulnerability Type**: Unrestricted URL fetch / client-side SSRF **Risk Level**: Medium ### Vulnerable Code ```python def _download_to_file(url: str, out_path: str, timeout_s: int = 300) -> Dict[str, Any]: """ Download a (possibly signed) URL to local file. Designed for OSS signed URLs returned by video generation tasks. """ os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True) req = urllib.request.Request(url, headers={"User-Agent": "OpenClaw-Media-Gen/1.0"}) try: with urllib.request.urlopen(req, timeout=timeout_s) as resp, open(out_path, "wb") as f: total = 0 while True: chunk = resp.read(1024 * 1024) # 1MB if not chunk: break f.write(chunk) total += len(chunk) return {"success": True, "saved_to": out_path, "bytes": total} except Exception as e: return {"success": False, "error": str(e), "url": url, "saved_to": out_path} ``` ```python if status == "SUCCEEDED" and getattr(args, "download", False): video_url = (resp.get("output") or {}).get("video_url") or (resp.get("output") or {}).get("videoUrl") if video_url: out_path = args.out or _safe_filename("mp4") dl = _download_to_file(video_url, out_path) resp = {**resp, "download": dl} ``` ### Technical Analysis The video download URL originates in the remote API response and is passed directly to `urllib.request.urlopen`. The implementation does not validate the URL scheme, hostname, resolved IP address, port, or redirect chain. Cross-domain downloads may be necessary because media-generation services commonly return signed object-storage URLs. However, unrestricted URL retriev ...[truncated 1850 chars]
- Remediation
- ## Remediation Suggestions 1. Permit only `https` download URLs. 2. Reject URLs containing embedded credentials. 3. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for both IPv4 and IPv6. 4. Validate every redirect target rather than validating only the initial URL. 5. Prefer an allowlist of documented AIsa object-storage domains where operationally possible. 6. Restrict destination ports to expected HTTPS ports. 7. Apply a maximum response size and validate the response content type before writing it as a video. 8. Consider requiring explicit user confirmation when the returned download host is outside a trusted allowlist.
