T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/generate-spell-mapping.mjs:1576
- Finding
- Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-spell-mapping.mjs`, lines 512–516, 639–655, 1576–1581, and 2057–2059 **Vulnerability Type**: Server-Side Request Forgery through user-provided, discovered, and redirected URLs **Risk Level**: High ### Vulnerable Code ```js if (token === "--url") { args.url = String(argv[index + 1] ?? "").trim(); index += 1; continue; } ``` ```js function canonicalizeReferenceUrl(value) { try { const url = new URL(String(value).trim()); if (!/^https?:$/i.test(url.protocol)) { return ""; } url.hash = ""; if (url.pathname !== "/") { url.pathname = url.pathname.replace(/\/+$/g, "") || "/"; } return url.toString(); } catch { return ""; } } ``` ```js const response = await fetch(reference.url, { headers: { accept: "application/json,text/html,application/xhtml+xml;q=0.9,*/*;q=0.8", "user-agent": USER_AGENT } }); ``` ```js async function fetchLoreFromUrl(url) { const html = await fetchText(url); const title = extractTitle(html); const description = extractMeta(html, "property", "og:description") || extractMeta(html, "name", "description"); const bodyText = stripHtmlToText(html).slice(0, 12000); return { mode: "url", source: url, title, summary: description, text: [title, description, bodyText].filter(Boolean).join("\n\n") }; } ``` ### Technical Analysis The `--url` argument accepts any URL that can be parsed by the standard `URL` constructor. The later canonicalization logic only restricts the protocol to HTTP or HTTPS. It does not reject: - Loopback destinations such as `127.0.0.1` and `[::1]` - Private network ranges - Link-local addresses - Cloud instance metadata services - Internal DNS names - DNS names that resolve or rebind to restricted addresses The generator directly fetches the supplied URL both as a spell-list candidate and as a lore source. It also fetches URLs discovered through search ...[truncated 2094 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Restrict network destinations** - Maintain an allowlist of trusted public origins needed for the declared functionality. - Require explicit opt-in before fetching arbitrary user-provided origins. - Do not infer or follow cross-origin endpoints unless separately approved. 2. **Validate resolved addresses** - Resolve hostnames before connecting. - Reject IPv4 and IPv6 loopback, private, link-local, multicast, reserved, and unspecified ranges. - Explicitly block cloud metadata destinations, including `169.254.169.254`. - Protect against DNS rebinding by validating the address actually used for each connection. 3. **Control redirects** - Use `redirect: "manual"`. - Resolve and validate every redirect destination before issuing the next request. - Apply a small redirect limit and reject HTTPS-to-HTTP downgrades. 4. **Limit resource use** - Add an `AbortController` timeout to every network request. - Enforce maximum response sizes before calling `text()` or parsing JSON. - Restrict content types to those necessary for spell-list and lore processing. 5. **Constrain discovery** - Prefer same-origin links. - Remove speculative endpoint probing for untrusted hosts. - Provide a heuristic-only or offline mode and make it the default where network discovery is unnecessary. 6. **Prevent indirect disclosure** - Avoid incorporating arbitrary remote response text into output without strict validation. - Do not include internal URLs in generated comments or diagnostic output. ]]>
