T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/image_generator.py:171
- Finding
- Unrestricted Server-Supplied Image URL Enables SSRF<![CDATA[ ## Vulnerability Details **File Location**: `scripts/image_generator.py`, lines 171–180 **Vulnerability Type**: Server-Side Request Forgery (SSRF) through an untrusted response URL **Risk Level**: High ### Vulnerable Code ```python elif "url" in img_data: try: img_url = img_data["url"] print(f"正在下载图像 {i+1}: {img_url}") img_response = requests.get(img_url, timeout=60) if img_response.status_code == 200: saved = save_image(img_response.content, filename) saved_files.append(saved) ``` ### Technical Analysis The configured image-generation service controls the `url` field in its API response. The script passes that value directly to `requests.get()` without validating: - The URL scheme - The destination hostname - The resolved IP address - Redirect destinations - Loopback, private, link-local, reserved, or cloud metadata addresses - Response content type - Response size Although downloading a generated image is part of the declared functionality, unrestricted retrieval from any server exceeds the minimum network access needed. A malicious or compromised API provider could direct the runtime to request internal resources such as `127.0.0.1`, private network services, or cloud metadata endpoints such as `169.254.169.254`. The response is read into memory through `img_response.content` and saved without a size limit or image validation. This additionally permits memory or disk exhaustion and allows arbitrary response content to be stored under a `.png` filename. ### Attack Path 1. A user configures the Skill to use a malicious or compromised OpenAI-compatible image API. 2. The user invokes the image-generation script with a prompt. 3. The API returns a syntactically valid response containing an attacker-selected URL, for example: ```json { "data": [ { "url": "http://169.254.169.254/latest/meta-data/" } ] } ``` 4. The script extracts the URL and performs a GET r ...[truncated 1369 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Restrict destination hosts** - Permit image downloads only from an explicit allowlist of trusted provider or CDN hostnames. - Do not accept arbitrary hosts solely because the generation API returned them. 2. **Require secure transport** - Allow only `https` URLs. - Reject URLs containing embedded credentials or unexpected ports. 3. **Block internal destinations** - Resolve the hostname before connecting. - Reject loopback, private, link-local, multicast, reserved, unspecified, and cloud metadata IP ranges for both IPv4 and IPv6. - Protect against DNS rebinding by ensuring that the validated address is the address used for the connection. 4. **Control redirects** - Disable automatic redirects or validate the scheme, hostname, port, and resolved address at every redirect hop. - Apply a small redirect limit. 5. **Limit downloaded content** - Use streamed downloads instead of reading the entire response into memory. - Enforce a strict maximum byte count based on expected image dimensions. - Abort if `Content-Length` exceeds the limit or if streamed content crosses it. 6. **Validate file contents** - Require an approved image media type. - Decode and verify the image with Pillow before saving it. - Reject malformed images and unsupported formats rather than relying on the `.png` extension. 7. **Reduce local file risks** - Write only within a designated output directory. - Sanitize the user-controlled output prefix and prevent absolute paths or path traversal. - Use exclusive file creation or randomized filenames to avoid unintended overwrites. A hardened implementation should combine destination allowlisting, IP-range checks, per-redirect validation, streaming size limits, and actual image decoding. Any one of these controls alone is insufficient against redirects, DNS rebinding, or oversized responses. ]]>
