T09 · Insecure Skill Coding Practices
- Location
scripts/html_to_markdown.mjs:221- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
controller.abort(), timeoutMs); try { const res = await fetch(url, { redirect: 'follow', signal: controller.signal }); if (!res.ok) throw new Error(`Fetch failed: ${res.status} ${res.statusText}`); return await res.text(); } finally { clearTimeout(timer); } } async function readInput(args) { if (args.file) return fs.readFile(args.file, 'utf8'); if (args.html) return args.html; if (args.url) return fetchWithTimeout(args.url, args.timeoutMs); throw new Error('No input'); } ``` The same unrestricted fetch function is used for URL-list batch processing: ```js for (const u of urls) { const out = path.join(args.outputDir, fileNameFromUrl(u)); try { const raw = await fetchWithTimeout(u, args.timeoutMs); const res = await convertOne(raw, args, u); await writeFileEnsure(out, res.markdown); ``` ### Technical Analysis The values supplied through `--url` and `--url-list` reach `fetch()` without validation of the URL scheme, destination hostname, resolved IP address, or network range. Although the command help presents an HTTPS URL, the implementation does not enforce HTTPS or restrict requests to public Internet addresses. The fetch operation also enables automatic redirects through `redirect: 'follow'`. Consequently, validating only the initial URL outside this function would not be sufficient: an apparently public endpoint could redirect the request to a loopback, private, link-local, or cloud metadata address. The response body is converted to Markdown and written to a caller-selected output file. Therefore, a user who can control the URL and subsequently read ...[truncated 1552 chars]- Remediation
View remediation
