T09 · Insecure Skill Coding Practices
- Location
index.js:76- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery (SSRF)
- Content
View full analysis
Vulnerability Details
File Location:
index.js:76-86
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: HighVulnerable Code
javascript /** * Fetch a webpage and convert it to Markdown. * @param {string} url - Target URL * @param {object} options - Options * @returns {Promise<object>} - Result object */ async function fetchAsMarkdown(url, options = {}) { try { // 1. Fetch webpage const response = await fetch(url, { headers: { ...DEFAULT_HEADERS, ...options.headers }, ...options.fetchOptions });The affected function is directly exposed to untrusted input by both command-line entry points:
cli.js:12-20,29webfetch-md-tool.js:17-25
Technical Analysis
fetchAsMarkdownpasses the supplied URL directly to the Node.jsfetchAPI without validating its scheme, hostname, resolved IP address, port, or redirect destinations.This allows callers to make HTTP requests using the network privileges of the process running the Skill. There are no controls blocking requests to:
- Loopback addresses such as
127.0.0.1or[::1] - RFC 1918 private networks
- Link-local addresses, including cloud instance metadata services
- Internal DNS hostnames
- Reserved or otherwise non-public address ranges
- Public endpoints that redirect to internal destinations
The default redirect behavior of
fetchcan also permit an initially public URL to redirect to a protected internal resource. Validating only the initial textual hostname would therefore be insufficient.After the request completes, the response body is parsed and converted to Markdown. The resulting content is returned to the caller, making this a response-disclosing SSRF rather than a blind SSRF.
The exported module API additionally allows callers to supply
options.headersandoptions.fetchOptions. In integrations where those values are influenced by an ...[truncated 1690 chars]- Remediation
View remediation
Remediation Suggestions
- Parse the input with
new URL(url)and reject malformed URLs. - Permit only explicitly required protocols, normally
https:and, if necessary,http:. Reject credentials embedded in URLs and all other schemes. - Resolve the hostname before connecting and reject every resolved IPv4 and IPv6 address that is loopback, private, link-local, multicast, unspecified, reserved, or otherwise non-public.
- Protect against DNS rebinding by ensuring the validated address is the address actually used for the connection. Consider using a controlled outbound proxy or custom dispatcher that enforces destination policy.
- Disable automatic redirects with
redirect: "manual"and validate every redirect target using the same protocol, hostname, and resolved-address checks. Set a small maximum redirect count. - Prefer an explicit hostname allowlist when the deployment has a known set of permitted sources.
- Add request timeouts, connection limits, and a maximum response-body size to reduce denial-of-service exposure.
- Restrict or remove caller-controlled headers and
fetchOptionsin untrusted integrations. Explicitly block sensitive forwarding headers such asAuthorization,Cookie, and proxy-related headers unless required. - Apply outbound firewall or sandbox rules so the Skill process cannot reach metadata endpoints, localhost services, or private networks.
- Add tests covering direct private addresses, IPv6 loopback, alternative numeric IP representations, internal DNS names, DNS rebinding, and public-to-private redirect chains.
- Parse the input with
