T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/kalshi_paper.ts:217
- Finding
- Unrestricted Market API Base URL Enables Blind Server-Side Request Forgery## Vulnerability Details **File Location**: `scripts/kalshi_paper.ts`, lines 217-245 **Vulnerability Type**: Blind Server-Side Request Forgery (SSRF) **Risk Level**: Medium ### Vulnerable Code ```ts function getKalshiBaseUrl(args: CliMap): string { const raw = (args["kalshi-base-url"] as string | undefined) ?? process.env.KALSHI_BASE_URL ?? "https://api.elections.kalshi.com/trade-api/v2"; return raw.replace(/\/+$/, ""); } async function fetchJson(url: string): Promise<unknown> { const res = await fetch(url, { method: "GET", headers: { accept: "application/json", "user-agent": "openclaw-skills-kalshi-paper-trading/1.0", }, }); const text = await res.text(); let json: unknown; try { json = JSON.parse(text); } catch { json = { raw: text }; } if (!res.ok) { throw new Error(`HTTP ${res.status} for ${url}: ${typeof json === "object" ? JSON.stringify(json) : String(json)}`); } return json; } ``` The resulting URL is used by `fetchKalshiMarket`: ```ts const baseUrl = getKalshiBaseUrl(args); const url = `${baseUrl}/markets/${encodeURIComponent(marketTicker)}`; const response = await fetchJson(url) as { market?: KalshiMarketPayload }; ``` ### Technical Analysis The `sync-market` and `buy-from-market` commands accept a network destination from either the `--kalshi-base-url` command-line option or the `KALSHI_BASE_URL` environment variable. The value is used without validating its scheme, hostname, port, resolved IP address, or redirect destination. Node.js `fetch` follows HTTP redirects by default. Therefore, restricting the final path to `/markets/<ticker>` does not prevent exploitation: an attacker-controlled initial server can redirect the request to a loopback, private-network, link-local, or cloud metadata address. Response-shape validation occurs only after the request and any redirects have completed. An invalid market response may stop database processing, but it does not pre ...[truncated 2071 chars]
- Remediation
- ## Remediation Suggestions 1. **Allowlist the production endpoint** - Permit only the official Kalshi HTTPS hostname during normal operation. - Compare parsed hostnames exactly rather than using suffix or substring checks. 2. **Validate the URL structurally** - Parse the value with the `URL` class. - Require `https:`. - Reject embedded credentials. - Reject fragments and unexpected ports. - Normalize the approved API path rather than accepting arbitrary base paths. 3. **Control redirects** - Set `redirect: "manual"` and reject redirects, or validate every redirect destination using the same policy before following it. - Do not rely only on validating the initial URL. 4. **Block internal destinations** - Resolve the hostname and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges. - Revalidate the connected destination to mitigate DNS rebinding and time-of-check/time-of-use issues. - Explicitly block cloud metadata addresses. 5. **Separate test configuration** - Permit arbitrary local endpoints only behind an explicit test-mode switch. - Ensure production Agent invocations cannot enable test mode through untrusted input. 6. **Limit request resource consumption** - Add an `AbortSignal` timeout. - Enforce a maximum response size before parsing or storing the body. - Avoid including complete remote response bodies in error messages. 7. **Add regression tests** - Verify rejection of HTTP URLs, embedded credentials, loopback addresses, private addresses, link-local addresses, unexpected ports, and redirect chains to prohibited destinations.
