T09 · Insecure Skill Coding Practices
- Location
scripts/generate_image.py:153- Finding
Unvalidated Server-Controlled Output URLs Permit Arbitrary Resource Retrieval
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_image.py, lines 153–166 and 294–295
Vulnerability Type: Unrestricted URL retrieval / server-side request forgery (SSRF)
Risk Level: MediumVulnerable code:
python def download_file(url, output_dir="."): parsed = urllib.parse.urlparse(url) filename = os.path.basename(parsed.path) if not filename or "." not in filename: filename = f"output_{int(time.time())}.png" output_path = os.path.join(output_dir, filename) base, ext = os.path.splitext(output_path) counter = 1 while os.path.exists(output_path): output_path = f"{base}_{counter}{ext}" counter += 1 print(f"Downloading: {filename}") urllib.request.urlretrieve(url, output_path) size_kb = os.path.getsize(output_path) / 1024 print(f"Saved: {output_path} ({size_kb:.1f} KB)") return output_pathpython saved = [] for url in outputs: saved.append(download_file(url, args.output))Technical Analysis
The script obtains output URLs from the Atlas Cloud API and passes each URL directly to
urllib.request.urlretrieve()without validating its scheme, hostname, port, resolved address, or redirect destinations. Parsing the URL only to derive a filename does not establish that the remote resource is trusted.This behavior contradicts the script's stated network boundary that network calls are limited to
api.atlascloud.ai. Python URL retrieval can access arbitrary HTTP or HTTPS hosts and may support other handlers, including localfile:resources. HTTP redirects are also followed without checking whether the destination remains within an approved Atlas-controlled domain.Image generation requires retrieving generated assets, but it does not require unrestricted access to arbitrary URLs. The implementation therefore exceeds the minimum network privileges necessary for the declared functionality ...[truncated 1892 chars]
- Remediation
View remediation
Remediation Suggestions
- Accept only
httpsoutput URLs. - Maintain an explicit allowlist of documented Atlas-controlled asset/CDN hostnames rather than accepting arbitrary Internet hosts.
- Reject URLs containing embedded credentials, unexpected ports, fragments, or malformed hostnames.
- Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified IP addresses for both IPv4 and IPv6.
- Disable automatic redirects or validate every redirect target using the same scheme, hostname, port, and resolved-address policy.
- Replace
urlretrieve()with a controlled downloader that enforces connection and read timeouts, maximum response size, and an expected image content type. - Verify downloaded content using image signatures or safe image decoding rather than trusting the filename extension or
Content-Typeheader alone. - Store downloads with locally generated filenames and restrictive permissions.
- Document the exact approved API and CDN domains in
SKILL.mdso the declared network boundary matches runtime behavior. - Consider having the trusted Atlas API return an asset identifier that is downloaded through a fixed, authenticated endpoint instead of returning an arbitrary URL.
- Accept only
