T09 · Insecure Skill Coding Practices
- Location
scripts/generate_meme.py:151- Finding
Unrestricted Download of a Server-Supplied URL Enables SSRF
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_meme.py, lines 151–162
Vulnerability Type: Server-Side Request Forgery through an unvalidated image URL
Risk Level: MediumVulnerable Code
python def _download_image(url: str) -> bytes: image_resp = requests.get(url, timeout=120) image_resp.raise_for_status() return image_resp.content def _extract_image_bytes(result: dict) -> bytes: data = result.get("data") or [] if not data: raise RuntimeError("图片接口未返回 data") first = data[0] if first.get("url"): return _download_image(first["url"])Technical Analysis
The image API response controls
data[0].url, which is passed directly torequests.getwithout validating:- The URL scheme
- The destination hostname
- The resolved IP address
- Redirect destinations
- The response content type
- The response body size
- Whether the body is a valid image
The configured model endpoint can therefore cause the runtime to make arbitrary outbound requests. This risk is amplified because
requests.getfollows redirects by default andMEME_MODEL_BASE_URLis configurable.This is an SSRF vulnerability rather than remote payload execution: the downloaded bytes are written to disk, but the audited code does not execute them.
Attack Path
- An attacker controls or compromises the configured OpenAI-compatible model endpoint.
- The victim invokes the Skill to generate an image.
- The malicious endpoint returns a response whose
data[0].urlpoints to a loopback, private-network, link-local, or cloud metadata address. _extract_image_bytesforwards the URL to_download_image.requests.getaccesses the target and follows any redirects without destination validation.- The target response is returned as image content and written to the configured output path.
Impact Assessment
An attacker controlling the ...[truncated 568 chars]
- Remediation
View remediation
Remediation Suggestions
- Prefer
b64_jsonAPI responses so the client does not need to retrieve a second server-selected URL. - If URL downloads remain necessary, require HTTPS and enforce an explicit allowlist of trusted image-host domains.
- Resolve the hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges for both IPv4 and IPv6.
- Disable redirects with
allow_redirects=False, or validate every redirect target using the same scheme, hostname, and resolved-address rules. - Account for DNS rebinding by ensuring that the validated address is the address used for the connection.
- Stream the response and enforce a strict maximum download size.
- Accept only expected image media types and verify the file signature and decodability before saving it.
- Apply outbound network controls that prevent the Skill process from reaching internal services and cloud metadata endpoints.
- Reject URLs containing embedded credentials or unsupported ports.
- Prefer
