T09 · Insecure Skill Coding Practices
- Location
scripts/image_recognize.py:88- Finding
Unrestricted Local File and URL Ingestion Enables Sensitive Data Disclosure and SSRF
- Content
View full analysis
Vulnerability Details
File Location:
scripts/image_recognize.py, lines 88–131
Vulnerability Type: Unrestricted file access, server-side request forgery, and external data disclosure
Risk Level: HighVulnerable Code
python # Handle network URLs if value.startswith(("http://", "https://")): try: response = requests.get(value, timeout=30) response.raise_for_status() return base64.b64encode(response.content).decode() except requests.RequestException as e: raise Exception(f"Failed to download network image: {e}") # Handle local file paths if os.path.exists(value): with open(value, "rb") as f: return base64.b64encode(f.read()).decode() else: raise FileNotFoundError(f"Image file does not exist: {value}") def recognize_image(image_b64: str, api_key: str) -> dict: """ Call the image-recognition API. Args: image_b64: Base64-encoded image api_key: Baidu API key Returns: API response """ api_url = QIANFAN_BASE_URL + "/v2/tools/image_general" api_url, headers = resolve_sandbox_url(api_url, api_key) payload = { "image_b64": image_b64 } try: response = requests.post(api_url, json=payload, headers=headers, timeout=30) response.raise_for_status()Technical Analysis
The
--imageargument is treated as either an unrestricted HTTP(S) URL or an arbitrary local file path. The code does not:- Restrict local access to an approved image or workspace directory.
- Resolve and validate paths against traversal or symbolic-link escapes.
- Verify that the input is a supported image by decoding its contents.
- Enforce the documented 4 MB size limit.
- Restrict URL destinations by hostname or resolved IP address.
- Block loopback, private, link-local, reserved, or cloud metadata addresses.
- Validate redirect destinatio ...[truncated 2533 chars]
- Remediation
View remediation
Remediation Suggestions
-
Constrain local file access
- Accept only files located within an explicitly approved upload or workspace directory.
- Canonicalize both the approved root and requested path with
Path.resolve(). - Reject paths outside the approved root and prevent symbolic-link escapes.
- Prefer file handles supplied by a trusted platform upload mechanism over arbitrary path strings.
-
Validate actual image contents
- Decode the input with a maintained image library and allow only required formats.
- Do not rely solely on filename extensions or response
Content-Type. - Reject malformed files, unsupported formats, and content that cannot be decoded as an image.
- Re-encode the decoded image before transmission to ensure unrelated embedded input is not forwarded unchanged.
-
Enforce resource limits
- Enforce the documented 4 MB maximum before Base64 conversion.
- Stream URL responses with a strict byte limit instead of loading unlimited response bodies into memory.
- Limit decoded dimensions and pixel counts to prevent decompression-bomb denial of service.
-
Prevent SSRF
- Resolve the destination hostname and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges.
- Allow only HTTP(S), preferably HTTPS.
- Disable redirects or validate every redirect destination using the same hostname and IP rules.
- Consider an explicit domain allowlist when remote image sources can be constrained.
- Apply network-level egress controls so the Skill cannot reach metadata, loopback, or private-network services.
-
Improve consent and disclosure
- Clearly disclose in
SKILL.mdthat selected image content is uploaded to Baidu. - Require explicit user confirmation before transmitting local files when the platform has not already obtained informed upload consent.
- Avoid logging Base64 image content, API credent ...[truncated 280 chars]
- Clearly disclose in
-
