T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/film-search.js:909
- Finding
- Unrestricted URL Resolution Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/film-search.js:909-923` **Additional Location**: `scripts/deep_extract.py:145-158` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```javascript async function cmdResolve(args) { const url = args.positional[0]; if (!url) { outputError("Please provide the URL to resolve."); process.exit(1); } try { // Fetch the page const resp = await fetch(url, { redirect: "follow", signal: AbortSignal.timeout(config.timeout), }); if (!resp.ok) throw new Error(`HTTP ${resp.status}`); const html = await resp.text(); ``` The Python extraction path contains a similar unrestricted request: ```python def fetch_and_extract(page, scraper): """Visit one page and extract all cloud-drive links.""" url = page.get('url', '') page_title = page.get('title', '') if not url: return [] try: r = scraper.get(url, timeout=8) if r.status_code != 200: sys.stderr.write(f'[extract] {url} -> HTTP {r.status_code}\n') return [] html = r.text ``` ### Technical Analysis The `resolve` command accepts a user-controlled URL and passes it directly to `fetch`. It does not validate: - The URL scheme - The destination hostname or resolved IP address - Loopback, private, link-local, multicast, or reserved networks - Cloud instance metadata addresses - Redirect destinations - DNS rebinding between validation and connection Because redirects are explicitly followed, an apparently public URL can redirect the request to an internal service. The Python extraction component has the same underlying weakness and accepts page URLs from JSON supplied through standard input. The response body is parsed for cloud-drive links rather than returned in full. This limits direct response disclosure, but does not prevent SSRF. An attacker may still infer service availability through st ...[truncated 1435 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse URLs with a strict URL parser and allow only `https:` unless plain HTTP is explicitly required. 2. Reject URLs containing credentials, malformed hostnames, or nonstandard encodings. 3. Resolve the hostname before connecting and reject every address in loopback, private, link-local, multicast, unspecified, and reserved ranges for both IPv4 and IPv6. 4. Explicitly block cloud metadata destinations, including link-local metadata addresses. 5. Disable automatic redirects and validate each redirect destination using the same controls before following it. 6. Protect against DNS rebinding by connecting only to the validated resolved address while preserving the expected hostname for TLS verification. 7. Prefer an allowlist of public domains appropriate to the resolver's intended purpose. 8. Apply the same validation routine to `deep_extract.py`, including URLs accepted from standard input and URLs discovered through search results. 9. Run outbound requests in a network sandbox that cannot access internal networks or metadata services. 10. Limit response size and supported content types to reduce secondary denial-of-service risks. ]]>
