T09 · Insecure Skill Coding Practices
- Location
scripts/zenmux_media_client.py:54- Finding
Unvalidated and Unbounded Downloads from API-Controlled URLs
- Content
View full analysis
Vulnerability Details
File Location:
scripts/zenmux_media_client.py, lines 54-70 and 155-166
Vulnerability Type: Server-Side Request Forgery-like behavior and resource exhaustion through unsafe media downloads
Risk Level: MediumVulnerable Code
python if "url" in image_data: # Download from URL img_response = requests.get(image_data["url"], timeout=30) img_data = img_response.content elif "base64" in image_data: img_data = base64.b64decode(image_data["base64"]) else: print(f"Unknown image format: {image_data}", file=sys.stderr) sys.exit(1) if out: with open(out, "wb") as f: f.write(img_data) print(f"Image saved to: {out}") return outpython video_url = status["output"]["url"] print(f"Downloading from: {video_url}") response = requests.get(video_url, timeout=300) response.raise_for_status() if out is None: out = f"{task_id}.mp4" with open(out, "wb") as f: f.write(response.content)Technical Analysis
The client trusts media URLs returned by the ZenMux API and passes them directly to
requests.get()without validating their scheme, hostname, resolved IP address, port, or redirect destination. If the API response is compromised or manipulated, the client can be induced to contact loopback, link-local, private-network, or cloud metadata endpoints using the network privileges of the local process.Both download paths also access
.content, which buffers the entire response in memory before writing it. Neither path imposes a maximum response size. A malicious endpoint can therefore return an oversized or indefinitely streamed response, potentially exhausting memory and subsequently disk space. The image path additionally does not callraise_for_status(), allowing HTTP error bodies to be accepted and written as image output.This network access is broader than the minimum privilege needed to downloa ...[truncated 1840 chars]
- Remediation
View remediation
Remediation Suggestions
- Allow only
httpsmedia URLs and reject URLs containing embedded credentials, unexpected ports, fragments, or unsupported schemes. - Maintain an explicit allowlist of documented ZenMux media hostnames rather than accepting arbitrary response destinations.
- Resolve the destination hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 addresses.
- Disable automatic redirects or validate the scheme, hostname, and resolved address again for every redirect target.
- Use streaming downloads with
stream=True, process fixed-size chunks, and enforce strict maximum image and video byte limits. - Check
Content-Lengthwhen available, while still enforcing the limit during streaming because that header may be absent or dishonest. - Call
raise_for_status()in the image download path before accepting response content. - Validate the returned media type using response headers and file signatures before saving it.
- Write downloads to a temporary file, abort and delete partial content when limits are exceeded, and atomically rename the file only after successful validation.
- Apply restricted network egress controls to the Skill process so it cannot access local, private, or metadata networks even if application-level validation is bypassed.
- Allow only
