T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/walk-next-game.mjs:34
- Finding
- Unvalidated Persisted Draft URL Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/lib/bracket-walk.mjs:176-182` - `scripts/walk-next-game.mjs:34-37` - `scripts/walk-apply-pick.mjs:49-55` **Vulnerability Type**: Server-Side Request Forgery (SSRF) through an attacker-controlled persisted URL **Risk Level**: High ### Vulnerable Code `scripts/lib/bracket-walk.mjs:176-182` reads the URL directly from the picks file without validation: ```js export const readWalkMeta = async (picksPath) => { try { const payload = await readJson(picksPath); return { draftToken: payload?.draftToken ?? null, draftApiUrl: payload?.draftApiUrl ?? null }; } catch { return { draftToken: null, draftApiUrl: null }; } }; ``` `scripts/walk-next-game.mjs:34-37` issues a GET request to that URL: ```js if (meta.draftToken && meta.draftApiUrl) { try { const res = await fetch(meta.draftApiUrl); if (res.ok) { ``` `scripts/walk-apply-pick.mjs:49-55` issues a PATCH request and transmits bracket state to that URL: ```js if (meta.draftToken && meta.draftApiUrl) { try { await fetch(meta.draftApiUrl, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ matchIndex: applied.gameIndex, winnerSeed }), }); ``` ### Technical Analysis The `draftApiUrl` value is loaded from a local picks-state JSON file. The CLI permits the picks file to be selected by the caller, and the metadata reader does not verify the URL's protocol, hostname, port, path, credentials, resolved IP address, or relationship to the configured BracketsBot frontend. Both `walk-next` and `walk-apply` subsequently pass this persisted value directly to `fetch()`. Consequently, anyone able to supply or modify a picks file can direct the process to send requests to arbitrary destinations, including: - Internet hosts controlled by an attacker - Loopback services such as `127.0.0.1` - Private-network services - Link-local or cloud metadata endpoints - Services reacha ...[truncated 1899 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not persist or trust a complete API URL. Persist only an opaque draft token and reconstruct the endpoint from a fixed, trusted origin. 2. Require HTTPS and enforce an exact hostname, port, and path allowlist before every request. 3. Reject URLs containing user information, fragments, unexpected query parameters, nonstandard ports, or non-HTTP schemes. 4. Resolve the hostname and reject loopback, private, link-local, multicast, and reserved IP ranges for both IPv4 and IPv6. 5. Disable automatic redirects or validate every redirect destination using the same policy. 6. Validate the draft token against a strict format before using it in a path. 7. Validate downloaded draft data before modifying local state. Require exactly the expected schema, bounds, and legal bracket progression. 8. Apply response-size limits and request timeouts to reduce denial-of-service exposure. 9. Consider cryptographically binding persisted metadata to the configured trusted origin if state files may cross trust boundaries. ]]>
