T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/generate.py:204
- Finding
- Unbounded Downloads from User-Controlled and API-Controlled URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py:204-239` **Vulnerability Type**: Unbounded network response handling and missing request timeouts **Risk Level**: Medium ### Vulnerable Code ```python print(f"Downloading from: {video_url}") response = requests.get(video_url) response.raise_for_status() with open(output_path, "wb") as f: f.write(response.content) ``` ```python if is_url(args.audio): # Download the audio first, then convert print(f"Downloading audio from URL: {args.audio}") response = requests.get(args.audio) response.raise_for_status() # Save to temp file ext = Path(urlparse(args.audio).path).suffix or ".mp3" fd, temp_audio = tempfile.mkstemp(suffix=ext) os.close(fd) with open(temp_audio, "wb") as f: f.write(response.content) ``` ### Technical Analysis The script downloads remote audio and generated video using `requests.get()` without connect or read timeouts. It also accesses `response.content`, which buffers the entire response in memory before writing it to disk. No maximum response size, `Content-Length` validation, streaming limit, media-type validation, or redirect policy is applied. The audio URL is directly controlled by the user. The video URL originates from the remote ComfyDeploy result and could become attacker-controlled if the service, workflow, account, or response is compromised. The absence of timeouts also affects availability because a server can accept a connection and then transmit data indefinitely or extremely slowly. ### Attack Path 1. An attacker supplies an HTTP or HTTPS URL through `--audio`. 2. The URL points to a server that returns an extremely large response, an endless stream, or a deliberately slow response. 3. The script calls `requests.get(args.audio)` without a timeout or size restriction. 4. Accessing `response.content` attempts to buffer the complete response in process memory. 5. The process hangs or exhausts memory; writin ...[truncated 675 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Set explicit connect and read timeouts, for example: ```python with requests.get( url, stream=True, timeout=(10, 60), allow_redirects=True, ) as response: response.raise_for_status() ``` - Stream downloads in bounded chunks instead of using `response.content`. - Maintain a byte counter and abort when a documented maximum audio or video size is exceeded. - Reject responses whose declared `Content-Length` exceeds the configured limit. - Validate `Content-Type` against an allowlist before processing the response. - Limit redirects and revalidate the scheme and destination after each redirect. - Consider restricting remote destinations or blocking private, loopback, link-local, and metadata-service addresses if URLs can be supplied by untrusted users. - Delete any partially written output if a download fails or exceeds its limit. ]]>
