T09 · Insecure Skill Coding Practices
- Location
scripts/kalshi-api.mjs:7- Finding
Unrestricted API Base URL Permits Arbitrary-Host GET Requests
- Content
View full analysis
Vulnerability Details
File Location:
scripts/kalshi-api.mjs, lines 7 and 43-51
Vulnerability Type: Unvalidated destination URL / limited server-side request forgery (SSRF)
Risk Level: MediumVulnerable Code
js const BASE_URL = process.env.KALSHI_BASE_URL || "https://api.elections.kalshi.com/trade-api/v2";js async function request(path, query = {}) { const url = `${BASE_URL}${path}${buildQuery(query)}`; const res = await fetch(url, { method: "GET", headers: { accept: "application/json", "user-agent": "openclaw-skills-kalshi-openapi-reader/1.0", }, });Technical Analysis
The
KALSHI_BASE_URLenvironment variable is used directly when constructing request URLs. The implementation does not parse or validate the configured URL's protocol, hostname, port, credentials, or resolved IP address.An attacker who can influence the environment of the CLI process can therefore redirect nominally Kalshi-related requests to an attacker-controlled host or a service reachable only from the execution environment. The request suffix is selected from hard-coded read-only endpoint paths such as
/exchange/status,/markets, and/events, which limits control over the complete path but does not prevent arbitrary-origin network access.The issue is a constrained SSRF-style condition rather than unrestricted request construction: only GET requests are sent, no authentication headers are attached, and endpoint suffixes remain controlled by the application. Nevertheless, the process may have network access unavailable to the attacker, allowing internal service discovery or retrieval of responses from predictable internal paths.
Attack Path
- The attacker obtains the ability to set or influence
KALSHI_BASE_URLin the environment used to launch the Skill. - The attacker sets the variable to an internal or attacker-controlled origin, for example `http:/ ...[truncated 1392 chars]
- The attacker obtains the ability to set or influence
- Remediation
View remediation
Remediation Suggestions
- Parse the configured value with
new URL()and reject malformed URLs. - Require the
https:protocol in production. - Allowlist the exact approved Kalshi API hostname and, if appropriate, the expected base path:
js const DEFAULT_BASE_URL = "https://api.elections.kalshi.com/trade-api/v2"; const configured = new URL( process.env.KALSHI_BASE_URL || DEFAULT_BASE_URL, ); const allowedHosts = new Set([ "api.elections.kalshi.com", ]); if (configured.protocol !== "https:" || !allowedHosts.has(configured.hostname) || configured.username || configured.password) { throw new Error("Invalid KALSHI_BASE_URL"); } const BASE_URL = configured.href.replace(/\/$/, ""); - If custom endpoints are required for local development, gate them behind an explicit development-only option rather than accepting arbitrary production environment values.
- For custom destinations, resolve the hostname and reject loopback, link-local, multicast, unspecified, and private IP ranges. Revalidate redirect targets or disable automatic redirects so an allowlisted host cannot redirect requests to a prohibited destination.
- Add tests confirming rejection of HTTP URLs, credential-bearing URLs, loopback addresses, private-network addresses, unapproved hostnames, and redirects to prohibited origins.
- Avoid returning complete destination URLs or raw response bodies to callers when they could contain sensitive internal information.
- Parse the configured value with
