T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/gen_music.py:50
- Finding
- Unvalidated API-Controlled Download URL Enables Blind SSRF and Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gen_music.py`, lines 50-54 and 91-107 **Vulnerability Type**: Unvalidated remote URL retrieval and unbounded response buffering **Risk Level**: Medium ### Vulnerable Code ```python def download_file(url: str, path: pathlib.Path, user_agent: str, verbose: bool): req = urllib.request.Request(url, headers={"User-Agent": user_agent}) if verbose: print(f"Downloading: {url}") with urllib.request.urlopen(req) as res: path.write_bytes(res.read()) ``` The URL passed to this function originates directly from the API response: ```python if status == "completed": audio_url = status_res.get("audio_url") if not audio_url and "audio_file" in status_res: audio_url = status_res["audio_file"].get("url") if not audio_url: # Some models might have it in result nesting audio_url = status_res.get("audio", {}).get("url") if not audio_url: raise SystemExit(f"Completed but no audio URL found: {status_res}") # Download out_dir = pathlib.Path(args.out_dir) out_dir.mkdir(parents=True, exist_ok=True) file_path = out_dir / f"music_{gen_id}.mp3" if args.verbose: print(f"Target path: {file_path}") download_file( audio_url, file_path, args.user_agent if hasattr(args, 'user_agent') else DEFAULT_USER_AGENT, args.verbose ) ``` ### Technical Analysis The script treats an `audio_url` supplied by AIMLAPI as trusted and passes it directly to `urllib.request.urlopen`. It does not validate the URL scheme, hostname, resolved IP address, port, or redirect destination. If AIMLAPI or its response path is compromised, the supplied URL can point to localhost, private network ranges, link-local services, cloud metadata endpoints, or another unintended network destination. This creates a blind server-side request forgery condition from the machine running the Skill. The response is also consumed using `res.rea ...[truncated 2231 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Allow only `https` download URLs. 2. Maintain an explicit allowlist of documented AIMLAPI media hostnames rather than accepting arbitrary domains. 3. Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified IP addresses for both IPv4 and IPv6. 4. Revalidate the destination after every redirect, or disable redirects entirely. Reject redirects to a different origin or non-HTTPS scheme. 5. Set explicit connection and read timeouts. 6. Stream the response in bounded chunks instead of calling `res.read()` without a limit. 7. Enforce a maximum permitted file size using both `Content-Length` and an independent byte counter while streaming. 8. Validate the response content type against expected audio formats, while recognizing that content type alone is not a security boundary. 9. Download to a temporary file and atomically rename it after successful validation. Delete partial files when an error or size violation occurs. 10. Consider using a maintained HTTP client with explicit timeout, redirect, and streaming controls. ]]>
