T09 · Insecure Skill Coding Practices
- Location
scripts/generate_image.py:35- Finding
Unrestricted Fetching of Model-Controlled URLs Enables SSRF and Data Exfiltration
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_image.py, lines 35-44, 67-75, and 131-136
Vulnerability Type: Server-Side Request Forgery through untrusted model output
Risk Level: HighVulnerable Code
python def _download_url(url: str, out_dir: str, idx: int) -> str: parsed = urlparse(url) ext = os.path.splitext(parsed.path)[1].lstrip(".") or "png" filename = f"openrouter_image_{int(time.time())}_{idx}.{ext}" path = os.path.join(out_dir, filename) r = requests.get(url, timeout=60) r.raise_for_status() with open(path, "wb") as f: f.write(r.content) return pathpython elif isinstance(content, str): if "data:image/" in content: for token in content.split(): if token.startswith("data:image/"): urls.append(token) if "http://" in content or "https://" in content: for token in content.split(): if token.startswith("http://") or token.startswith("https://"): urls.append(token)python paths = [] for i, u in enumerate(urls): if u.startswith("data:image/"): paths.append(_save_data_url(u, out_dir, i)) else: paths.append(_download_url(u, out_dir, i)) return pathsTechnical Analysis
The script considers arbitrary HTTP or HTTPS tokens found in model-generated text to be image URLs. It subsequently sends server-side requests to those URLs without validating:
- The destination hostname
- The resolved IP address
- Whether the address belongs to a loopback, private, link-local, multicast, or reserved network
- Redirect destinations
- The response MIME type
- Whether the response is actually an image
OpenRouter responses and model-generated content must be treated as untrusted input. A crafted prompt, prompt-influenced model response, or compromised upstream service can cause the script to req ...[truncated 2058 chars]
- Remediation
View remediation
Remediation Suggestions
- Prefer accepting only inline
data:image/*;base64results from OpenRouter, eliminating arbitrary secondary network requests. - If remote downloads are required, maintain an explicit allowlist of trusted HTTPS hostnames documented by the image provider.
- Reject HTTP and all unsupported URL schemes.
- Resolve the hostname before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses.
- Disable redirects or validate every redirect destination with the same hostname and IP-address controls.
- Protect against DNS rebinding by ensuring that the validated address is the address used for the connection.
- Require an expected image MIME type and verify image magic bytes before saving or forwarding the response.
- Do not derive the file extension directly from an untrusted URL. Select it only after validated image-type detection.
- Avoid extracting URLs from arbitrary natural-language response text. Parse only documented, structured image response fields.
- Ensure Telegram delivery occurs only after successful image validation.
- Prefer accepting only inline
