T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/extract-paper-records.mjs:278
- Finding
- Unrestricted Server-Side Request Forgery Through User-Controlled URLs and Redirects<![CDATA[ ## Vulnerability Details **File Location**: `scripts/extract-paper-records.mjs:278-291, 318-319` **Vulnerability Type**: Server-Side Request Forgery **Risk Level**: High ### Vulnerable Code ```js async function fetchSource(url) { const response = await fetch(url, { redirect: "follow", headers: { "user-agent": "paper-cluster-survey-v2-2/1.0", accept: "text/html,application/pdf;q=0.9,*/*;q=0.8", }, }); const contentType = response.headers.get("content-type") || ""; const buffer = Buffer.from(await response.arrayBuffer()); return { url: response.url, ok: response.ok, status: response.status, contentType, buffer, }; } ``` ```js async function extractFromUrl(record) { const notes = []; try { const fetched = await fetchSource(record.url); ``` ### Technical Analysis The extractor accepts any syntactically valid HTTP or HTTPS URL and passes it directly to `fetch()`. It does not restrict destination hosts, resolve and validate destination IP addresses, or reject loopback, private, link-local, multicast, and reserved address ranges. The `redirect: "follow"` option also causes redirects to be followed automatically without validating each redirect destination. Consequently, an initially public URL can redirect the request to an internal service even if validation is later added only to the original URL. Responses are captured in memory and subsequently processed as HTML, text, or PDF content. This makes the issue observable rather than blind SSRF: portions of a successfully retrieved internal response may appear in generated paper records. ### Attack Path 1. An attacker supplies a source such as a loopback, private-network, link-local, or public redirect URL. 2. The source is accepted because URL validation checks only for the `http:` or `https:` scheme. 3. `extractFromUrl()` passes the URL to `fetchSource()`. 4. `fetch()` connects using the network privileges of the Agent process and automa ...[truncated 918 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Introduce a centralized outbound URL validator that permits only required HTTP and HTTPS destinations. 2. Resolve hostnames before connecting and reject all addresses in loopback, private, link-local, multicast, unspecified, and reserved ranges for both IPv4 and IPv6. 3. Explicitly block common metadata destinations, including `169.254.169.254`, even when referenced through alternate numeric forms or DNS names. 4. Disable automatic redirects. Follow redirects manually and repeat scheme, hostname, port, and resolved-IP validation for every hop. 5. Consider an allowlist of recognized scholarly and publisher domains when the deployment model permits it. 6. Restrict destination ports to expected web ports. 7. Protect against DNS rebinding by ensuring the validated address is the address used for the connection. 8. Run extraction in a sandbox with restricted network egress and no access to internal management networks. 9. Avoid returning sensitive internal response bodies in extraction notes or generated records. 10. Add tests covering loopback addresses, RFC 1918 ranges, IPv6 local addresses, alternate IP encodings, redirects to private hosts, and DNS rebinding scenarios. ]]>
