Any Web Page Could Spend Your OpenAI Key: Cross-Site WebSocket Hijacking in Headroom (CVE-2026-71416)
Among the agent-attack-surface advisories newly listed across the major databases this week is a High-severity classic wearing agentic clothes: CVE-2026-71416 (GHSA-h46j-26q3-rggf) in Headroom (headroomlabs-ai/headroom), an OpenAI API proxy. Its WebSocket endpoint never validated the Origin header before accepting client connections — and when a caller omitted credentials, the server helpfully injected its own OPENAI_API_KEY. Together, those two behaviours meant any web page rendered in a browser with a network route to the proxy could issue arbitrary LLM requests billed to the victim’s OpenAI account, no key required. Affected: pip headroom-ai < 0.35.0. Fixed in 0.35.0.
The vulnerable handler is ws://<headroom_host>:8787/v1/responses, the proxy path for the Responses API that newer Codex versions (gpt-5.4+) use over WebSocket instead of HTTP POST. The advisory’s proof of concept is a few lines of page JavaScript: open the socket, send a response.create with attacker-chosen model, instructions, input and tools — including a local-shell tool and the input “Run the id command for the logged in user.” The upstream API accepted the request (the PoC transcript ends in an insufficient_quota billing error, which is itself the proof: an unauthenticated cross-origin caller got far enough to be billed).
The convenience feature that deleted the auth boundary
Either half of this bug alone would be a lesser finding. A missing Origin check on an endpoint that still demands authentication is a nuisance; a server-side key fallback on an endpoint with proper origin gating is a design choice. Headroom combined them. The code comment quoted in the advisory is admirably honest about intent: “Safety net for clients that don’t forward auth headers via WebSocket upgrade.” If the handshake carried no Authorization header, the server read OPENAI_API_KEY from its environment and attached it upstream. The attacker’s optimal strategy was therefore to authenticate as nobody — the server upgraded them to the victim.
Note the exploitation preconditions, because they define who should worry. The malicious page must run in a browser — classic or headless — with network access to the proxy. A proxy bound to 127.0.0.1 on a developer laptop is reachable from every page that developer opens; one bound to 0.0.0.0 (as in the advisory’s own PoC command) is reachable from the LAN. This is CSWSH in its textbook form, transplanted into the LLM-proxy layer the agent ecosystem spent 2026 building.
Billing is the blast radius — and prompts are the payload
The advisory is careful about what was proven: arbitrary instructions, inputs and tools on the victim’s key, with quota burn as the floor. But dwell on what “arbitrary” means against an agentic Responses endpoint: the PoC didn’t just ask for text, it requested tool use. Every call lands on the victim’s usage record, against their rate limits and budget, under their account identity. And the pattern generalises to the whole class of local LLM gateways — the proxies, routers and “bring your own key” shims teams run so agents can share one credential. Each one is a place where the key lives one missing header check away from whoever can open a socket.
It also pairs uncomfortably with the credential-trail problem: agents already scatter provider credentials across predictable endpoint paths, and one agent compromise has been shown to convert into every connected third-party token. Headroom’s flaw needed no compromise at all — just a page, a socket, and a missing Origin check. The same week’s other browser-seam finding, an MCP bridge’s CORS origin bypass, rhymes: the agent stack keeps forgetting that the browser is hostile input.
What to do now
- Upgrade to
headroom-ai0.35.0 or later. Then confirm the running instance actually restarted onto it — proxies are long-lived processes that outlive their own upgrades. - Bind the proxy to loopback unless LAN access is a real requirement. Never
--host 0.0.0.0by default; every extra network that can route to port 8787 is a population of potential calling pages. - Enforce an Origin allowlist at the proxy layer and require explicit authentication on every WebSocket handshake — no environment-variable fallback for anonymous callers.
- Scope the key the proxy holds. A dedicated key with tight spend limits and usage alerts converts the next flaw in this class from an incident into an anomaly. Review OpenAI usage dashboards for
response.createcalls you can’t attribute. - Audit the rest of your local LLM gateway fleet the same way. Any “convenience” proxy that injects credentials for unauthenticated local callers has the same shape; check its handshake validation before an attacker’s page does.
Our verification was primary-source-led and static. We read the reviewed advisory GHSA-h46j-26q3-rggf in full — package and version range, severity, the unvalidated-Origin handler and file references, the OPENAI_API_KEY fallback logic, and the complete proof-of-concept transcript including the upstream insufficient_quota response — and confirmed the CVE-2026-71416 identifier as published. The advisory’s publication date (27 August 2026) predates this briefing; it reached our coverage via the 3 October roundup of advisories newly listed across the major agent-vulnerability feeds. We did not install Headroom, run the proxy, or attempt exploitation; impact statements are the advisory authors’ own.
Sources: