T09 · Insecure Skill Coding Practices
- Location
scripts/rss.js:41- Finding
Arbitrary Feed URLs Enable Server-Side Request Forgery
- Content
View full analysis
{ const client = url.startsWith('https') ? https : http; const req = client.get(url, { headers: { 'User-Agent': 'Clawdbot-RSS/1.0' }, timeout: 10000 }, (res) => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { // Follow redirect return fetchUrl(res.headers.location).then(resolve).catch(reject); } if (res.statusCode !== 200) { reject(new Error(`HTTP ${res.statusCode}`)); return; } let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => resolve(data)); }); req.on('error', reject); req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); }); }); } ``` The user-controlled URL reaches this function during feed validation: ```javascript const xml = await fetchUrl(url); ``` ### Technical Analysis The `add` command accepts a user-provided feed URL and passes it to `fetchUrl()` without validating its destination. Stored feed URLs are subsequently fetched by the `check` command as well. The implementation does not: - Reject loopback, private, link-local, or multicast IP addresses. - Prevent access to cloud instance metadata endpoints. - Resolve hostnames and validate all returned IP addresses. - Revalidate the destination after redirects. - Impose a maximum redirect count. - Restrict destinations to a trusted host allowlist. An attacker can therefore cause the process to issue HTTP requests to services reachable from the host running the Skill. A public URL can also redirect to an internal address, bypassing valid ...[truncated 2023 chars]- Remediation
View remediation
