T09 · Insecure Skill Coding Practices
- Location
index.js:42- Finding
Unrestricted Feed URLs Enable Server-Side Request Forgery (SSRF)
- Content
View full analysis
{ const parsedUrl = new URL(url); const protocol = parsedUrl.protocol === 'https:' ? https : http; const req = protocol.get(url, { headers: { 'User-Agent': 'feed-w0', 'atcher/1.Accept': 'application/rss+xml, application/atom+xml, application/xml, text/xml' } }, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => resolve(data)); }); req.on('error', reject); req.setTimeout(10000, () => { req.destroy(); reject(new Error('Request timeout')); }); }); } ``` The URL reaches the vulnerable function directly when a feed is added: ```js await addFeed(args[1], args[2]); ``` Stored feed URLs are fetched again during later checks: ```js const xml = await fetchFeed(feed.url); const items = parseFeed(xml, feed.url); ``` ### Technical Analysis The `add` command accepts an arbitrary URL from the command line, and `addFeed()` passes it to `fetchFeed()` without validating its destination. The URL is also persisted in `~/.feed-watcher/feeds.json`, allowing later `check` or `scan` operations to repeat the request. The implementation does not reject: - Loopback destinations such as `127.0.0.1` or `[::1]` - RFC 1918 private networks - IPv6 unique-local or link-local networks - IPv4 link-local destinations such as `169.254.0.0/16` - Cloud instance metadata endpoints - Internal hostnames that resolve to protected addresses - Plaintext HTTP destinations Consequently, the process can be induced to make HTTP requests using its own network position. This violates least privilege because public-fee ...[truncated 2064 chars]- Remediation
View remediation
