T09 · Insecure Skill Coding Practices
- Location
routes/ingest.js:22- Finding
Incomplete SSRF Protection Allows Requests to Internal Network Resources
- Content
View full analysis
{ 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
View remediation
