T09 · Insecure Skill Coding Practices
- Location
scripts/generate.py:330- Finding
Unrestricted Retrieval of Server-Supplied URLs Enables SSRF and Resource Exhaustion
- Content
View full analysis
None: req = urllib.request.Request( url, headers={"User-Agent": "OpenClaw ERNIE-Image Skill"} ) try: with urllib.request.urlopen(req, timeout=180) as resp: data = resp.read() except Exception as exc: raise RuntimeError(f"Failed to fetch generated image: {exc}") from None out_path.write_bytes(data) ``` ```python def save_outputs(response: dict, response_format: str, out_dir: Path) -> None: for index, item in enumerate(response_items(response), start=1): if response_format == "url": url = item.get("url") if not url: raise RuntimeError(f"Image item missing URL: {item}") print(f"IMAGE_URL:{url}") out_path = out_dir / timestamp_name(index, extension_from_url(url)) download_url(url, out_path) ``` ### Technical Analysis The image URL is obtained directly from the remote API response and passed to `urllib.request.urlopen()` without validating its scheme, hostname, resolved address, port, or redirect chain. The downloader does not: - Require HTTPS. - Restrict destinations to documented Baidu or approved CDN domains. - Reject loopback, private, link-local, reserved, or multicast IP addresses. - Revalidate destinations after HTTP redirects. - Defend against DNS rebinding. - Verify that the response has an expected image media type or valid image signature. - Enforce a maximum response size. Consequently, a compromised API endpoint, manipulated response, malicious CDN path, or unsafe redirect could direct the process to an internal service such as `127.0.0.1`, an RFC1918 address, or a cloud metadata endpoint. Although the outbound request does n ...[truncated 2419 chars]- Remediation
View remediation
