T09 · Insecure Skill Coding Practices
- Location
src/web-clip.js:37- Finding
SSRF Protection Can Be Bypassed Through DNS Resolution
- Content
View full analysis
5) return Promise.reject(new Error('Too many redirects')); // Block internal/metadata URLs const parsed = new URL(url); const h = parsed.hostname.replace(/^\[|\]$/g, ''); // Strip IPv6 brackets if (/^(127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.|0\.|localhost$|::1$|::ffff:|0{1,4}:|fe80:)/i.test(h)) { return Promise.reject(new Error('Blocked: internal URL')); } const client = url.startsWith('https') ? https : http; return new Promise((resolve, reject) => { const req = client.get(url, { headers: { 'User-Agent': 'WebClip/1.0' }, timeout: 10000 }, res => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { return this._get(res.headers.location, _redirects + 1).then(resolve).catch(reject); } let data = ''; const maxSize = 10 * 1024 * 1024; // 10MB max res.on('data', c => { data += c; if (data.length > maxSize) { req.destroy(); reject(new Error('Response too large')); } }); res.on('end', () => resolve(data)); }); req.on('error', reject); req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')); }); }); } ``` ### Technical Analysis The internal-network restriction validates only the textual hostname supplied in the URL. It does not resolve the hostname and inspect the IP addresses to which the Node.js networking stack will connect. Consequently, an attacker-controlled public-looking hostname may pass the regular expression and subsequently resolve to a loopback, private, link-local, or cloud metadata address. DNS rebinding can also cause a hostname to resolve to an acceptable address during validation and an internal address when the connection occurs. Variants not covered by the textual regu ...[truncated 1841 chars]- Remediation
View remediation
