T09 · Insecure Skill Coding Practices
- Location
references/url_downloader.py:94- Finding
Unrestricted URL Download Enables Server-Side Request Forgery
- Content
View full analysis
Vulnerability Details
File Location:
references/url_downloader.py:94-110, with the unvalidated URL reaching the download functions atreferences/url_downloader.py:427-477
Vulnerability Type: Server-Side Request Forgery
Risk Level: HighVulnerable Code
python def curl_download(url: str, save_dir: str, timeout: int = 30): temp_path, headers_path = get_unique_temp_path(save_dir, "curl") cmd = [ "curl", "-s", "-L", "-o", temp_path, "-D", headers_path, "-w", "%{http_code}", "--max-time", str(timeout), ] for k, v in HEADERS.items(): cmd += ["-H", f"{k}: {v}"] cmd.append(url) try: result = subprocess.run( cmd, capture_output=True, text=True, timeout=timeout + 5 )The unvalidated URL is selected and passed to the network clients as follows:
python os.makedirs(save_dir, exist_ok=True) handler = resolve_handler_by_url(url) if handler: print(f"[download_file] detected a dedicated URL pattern") return handler(url, save_dir) if try_curl_first: print(f"[curl] attempting direct download: {url[:80]}") result = curl_download(url, save_dir) if result and is_attachment_file(result): return result if not filename_hint: parsed = urlparse(url) path_part = parsed.path.split("/")[-1] filename_hint = ( path_part if path_part and "." in path_part else "invoice.pdf" ) result = playwright_download(url, save_dir, filename_hint) if result and is_attachment_file(result): return resultTechnical Analysis
The Skill extracts URLs from email bodies and passes them directly to
curland, if the direct download fails, Playwright. It does not:- Restrict URLs to HTTPS.
- Allowlist trusted invoice-provider domains.
- Resolve and inspect the destination IP address.
- Block loopback, private, link-local, multicast, or reserved address ranges.
- Vali ...[truncated 2247 chars]
- Remediation
View remediation
Remediation Suggestions
- Permit only
httpsURLs and reject URLs containing credentials, unusual ports, fragments, or unsupported schemes. - Maintain an explicit allowlist of exact invoice-provider hostnames rather than accepting arbitrary email-supplied destinations.
- Resolve the hostname before connecting and reject every resolved loopback, private, link-local, multicast, unspecified, and reserved address.
- Revalidate the hostname and resolved IP address after every redirect. Do not rely on
curl -Lto follow redirects without application-level checks. - Restrict curl explicitly, for example with protocol and redirect-protocol controls, while still performing application-level destination validation.
- Defend against DNS rebinding by binding the validated hostname to the validated address or using a controlled outbound proxy.
- Apply equivalent routing restrictions to Playwright, including request interception that aborts navigation and subresource requests to prohibited destinations.
- Apply strict response size, content type, and timeout limits.
- Log rejected destinations without recording sensitive URL query parameters.
- Permit only
