T09 · Insecure Skill Coding Practices
- Location
- routes/ingest.js:22
- Finding
- Incomplete SSRF Protection Allows Requests to Internal Network Resources<![CDATA[ ## Vulnerability Details **File Location**: `routes/ingest.js:22-49`, with vulnerable request sinks at `routes/ingest.js:70-72` and `routes/ingest.js:106` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```js const ssrfProtection = async (req, res, next) => { const { sourceType, url } = req.body; if (sourceType === 'url' && url) { try { const parsedUrl = new URL(url); // 1. Enforce safe protocols if (!['http:', 'https:'].includes(parsedUrl.protocol)) { return res.status(400).json({ error: "Security Exception: Only HTTP and HTTPS protocols are allowed." }); } const hostname = parsedUrl.hostname; // 2. Resolve the hostname to its actual IP address to prevent DNS rebinding const lookup = await dns.lookup(hostname); const resolvedIp = lookup.address; // 3. Block local and private IP ranges const isLocalOrPrivate = /^(localhost|127\.0\.0\.1|0\.0\.0\.0|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2[0-9]|3[0-1])\.\d+\.\d+|169\.254\.\d+\.\d+|::1)$/i.test(resolvedIp) || hostname.toLowerCase() === 'localhost'; if (isLocalOrPrivate) { return res.status(403).json({ error: "Security Exception: Access to local or private networks is strictly forbidden." }); } } catch (err) { return res.status(400).json({ error: "Security Exception: Malformed URL or DNS resolution failed." }); } } next(); }; ``` The URL is subsequently fetched without binding the request to the validated address or revalidating redirects: ```js if (lowerUrl.endsWith('.mp4')) { const tempVideoPath = path.join(sessionDir, 'downloaded.mp4'); const response = await axios({ method: 'GET', url: url, responseType: 'stream' }); const writer = fs.createWriteStream(tempVideoPath) ...[truncated 2939 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse supplied URLs with a strict URL parser and allow only `http:` and `https:`. 2. Resolve all A and AAAA records and reject the request if any result is non-public. 3. Use a maintained IP-address library rather than a regular-expression denylist. Reject loopback, private, link-local, unique-local, multicast, unspecified, reserved, documentation, carrier-grade NAT, and IPv4-mapped IPv6 ranges. 4. Disable automatic redirects, or process redirects manually and repeat complete URL and DNS validation for every destination. 5. Prevent DNS rebinding by connecting to the exact validated IP address while preserving the original hostname for the HTTP `Host` header and TLS certificate verification. 6. Apply outbound network controls at the operating-system or container level to block access to loopback, private subnets, and metadata endpoints. 7. Enforce response-size and download-time limits for both MP4 and HTML retrieval to reduce resource-exhaustion exposure. 8. Add tests covering redirects to private addresses, multiple DNS answers, IPv6 private ranges, IPv4-mapped IPv6 addresses, unusual numeric address formats, and DNS rebinding behavior. ]]>
