T09 · Insecure Skill Coding Practices
Warning
- Location
- content.js:34
- Finding
- Unrestricted URL Fetching Enables Server-Side Request Forgery## Vulnerability Details **File Location**: `content.js:8, 34-43`; `search.js:120-127, 156` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: Medium ### Vulnerable Code `content.js:8`: ```js const url = process.argv[2]; ``` `content.js:34-43`: ```js try { const response = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.9", }, signal: AbortSignal.timeout(15000), }); ``` `search.js:120-127`: ```js async function fetchPageContent(url) { try { const response = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", }, signal: AbortSignal.timeout(10000), }); ``` `search.js:156`: ```js result.content = await fetchPageContent(result.link); ``` ### Technical Analysis The `content.js` entry point accepts a URL directly from a command-line argument and passes it to `fetch()` without validating its protocol, hostname, resolved IP address, port, or redirect destinations. Consequently, an untrusted caller can direct the process to issue HTTP requests from the Agent's network environment. The optional content-fetching behavior in `search.js` has the same underlying weakness. URLs extracted from search results are passed to `fetchPageContent()` without destination validation. Because `fetch()` follows HTTP redirects by default, an initially public URL may redirect to a loopback, link-local, private-network, or cloud metadata address. Neither implementation blocks IPv4 or IPv6 private ranges, loopback addresses, link-local address ...[truncated 2065 chars]
- Remediation
- ## Remediation Suggestions 1. Parse inputs with the standard `URL` class and permit only explicitly required protocols, preferably `https:` and, if necessary, `http:`. 2. Reject URLs containing embedded credentials, malformed hostnames, unsupported ports, or non-HTTP schemes. 3. Resolve the destination hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, documentation, and reserved IPv4 and IPv6 ranges. 4. Disable automatic redirects or process redirects manually. Apply the complete protocol, hostname, port, and resolved-address validation to every redirect target. 5. Defend against DNS rebinding by ensuring the validated address is the address used for the connection, or by using a hardened outbound proxy that enforces destination policy. 6. Prefer an explicit allowlist of trusted domains when the expected set of content sources is known. 7. Block cloud metadata destinations explicitly, including link-local metadata addresses and provider-specific metadata hostnames. 8. Apply strict response-size limits while streaming the body rather than calling `response.text()` without a bound. 9. Validate response content types and reject unexpected binary or active content. 10. Enforce outbound firewall or proxy rules so the Skill cannot reach internal networks or metadata services even if application-level validation is bypassed. 11. Return generic request errors where possible to reduce internal host and port enumeration through status, timing, and connection-error differences.
