T09 · Insecure Skill Coding Practices
Error
- Location
- content.js:43
- Finding
- Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `content.js:12, 43-50`; `search.js:70, 83, 131-138, 163-165` **Vulnerability Type**: Server-Side Request Forgery through unrestricted URL fetching **Risk Level**: High ### Vulnerable Code In `content.js`, a command-line argument is accepted as a URL and passed directly to `fetch()`: ```js const url = process.argv[2]; 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), }); ``` In `search.js`, links extracted from remotely supplied Brave Search HTML are stored and later fetched when `--content` is enabled: ```js const link = titleLink.getAttribute('href'); if (!link || link.includes('brave.com')) continue; const titleEl = titleLink.querySelector('.title'); const title = titleEl?.textContent?.trim() || titleLink.textContent?.trim() || ''; const descEl = snippet.querySelector('.generic-snippet .content'); let snippetText = descEl?.textContent?.trim() || ''; snippetText = snippetText.replace(/^[A-Z][a-z]+ \d+, \d{4} -\s*/, ''); if (title && link) { results.push({ title, link, snippet: snippetText }); } ``` ```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), }); ``` ```js if (fetchContent) { for (const result of results) { result.content = await fetchPageContent(result.link); } } ``` ### Technical Analysis Neither fetching path validates the destination before opening a network connection. The implementation lacks: - An `http:` and ...[truncated 3296 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse every destination with the standard `URL` class and reject malformed URLs. 2. Permit only explicitly supported schemes: ```js const parsed = new URL(input); if (!["http:", "https:"].includes(parsed.protocol)) { throw new Error("Unsupported URL scheme"); } ``` 3. Reject URLs containing embedded usernames or passwords. 4. Resolve the hostname before connecting and reject every resolved IPv4 or IPv6 address belonging to: - Loopback ranges. - Private ranges. - Link-local ranges. - Multicast ranges. - Unspecified or reserved ranges. - IPv4-mapped IPv6 representations of prohibited IPv4 addresses. - Known cloud metadata destinations. 5. Disable automatic redirects with `redirect: "manual"`. If redirects are needed, parse, resolve, and validate each new destination before issuing the next request. Apply a strict redirect-count limit. 6. Mitigate DNS rebinding by ensuring the validated IP is the address used for the connection, or by revalidating resolution at connection time through a controlled HTTP agent. 7. Restrict destination ports to an explicit allowlist, normally ports 80 and 443, unless additional ports are required. 8. Apply outbound network controls at the process, container, or firewall layer. Block access to localhost, private networks, and metadata endpoints even if application-level validation is bypassed. 9. Enforce a maximum response body size while streaming instead of calling `response.text()` without a limit. 10. Validate response `Content-Type` and accept only the document types required for content extraction. 11. Apply the same validation function to both: - The command-line URL in `content.js`. - Every result URL and redirect target fetched by `search.js`. 12. Add regression tests covering direct IP addresses, encoded addresses, IPv6, IPv4-mapped IPv6, alternative host representations, DNS rebinding scenarios, and public URLs redirecting to private destinations. ...[truncated 4 chars]
