flawopen.com/Teardowns/cve-2026-71416-headroom-websocket-origin-hijacking
CVE-2026-71416: Headroom-WebSocket-Origin-Hijacking
Headroom prüfte WebSocket-Origin nicht; eine besuchte Seite konnte LLM-Anfragen über den Proxy senden. Aktualisieren Sie auf 0.35.0+.
Ein Empfang lässt alle an einen privaten Schalter, weil der Besucherausweis ungeprüft bleibt. Origin ist dieser Ausweis: Der Proxy muss ihn prüfen, bevor er einen Kanal öffnet, der den gespeicherten API-Schlüssel verwenden kann.
Kernkonzepte & Begriffe
WebSocket- Dauerhafte bidirektionale Verbindung, die mit einer HTTP-Upgrade-Anfrage beginnt und Nachrichten in beide Richtungen überträgt.
Origin-Header- Vom Browser gesendetes Schema, Host und Port der Seite, die eine Anfrage ausgelöst hat. Beim WebSocket-Handshake muss der Server eine eigene Vertrauensrichtlinie anwenden; CORS-Header ersetzen diese Prüfung nicht.
CSWSH- Cross-Site WebSocket Hijacking: Eine nicht vertrauenswürdige Seite öffnet einen WebSocket zu einem erreichbaren Dienst, der den Ursprung nicht prüft.
Umgebungsberechtigung- Ein Geheimnis, das dem Prozess bereits zur Verfügung steht, etwa ein API-Schlüssel in einer Umgebungsvariable, und Anfragen ohne eigene Client-Anmeldedaten authentifizieren kann.
CWE-1385- Fehlende Origin-Prüfung bei WebSockets: Der Endpunkt prüft nicht, ob der Kommunikationsursprung zugelassen ist.
Framework-Zuordnungen
- CWE-Referenz für die in diesem Leitfaden beschriebene Schwachstelle: CWE-1385
- OWASP GenAI 2025 — LLM06:2025 Übermäßige Autonomie
Ursachenanalyse
Headrooms WebSocket-Handler /v1/responses akzeptierte die Browserverbindung, bevor er Origin im Handshake prüfte. Danach konnte der Proxy OPENAI_API_KEY aus seiner eigenen Umgebung zur Upstream-Anfrage hinzufügen. Die Same-Origin-Policy des Browsers verhindert nicht automatisch, dass JavaScript einen WebSocket zu einem anderen erreichbaren Host öffnet; der Browser sendet normalerweise Origin, und der Server muss Ursprünge außerhalb seiner Richtlinie ablehnen. Ein Angriff setzt daher voraus, dass der Browser eines Opfers einen verwundbaren Headroom-Proxy erreichen kann und der Proxy über nützliche Zugangsdaten oder Integrationen verfügt. Der Hinweis besagt, dass eine akzeptierte Verbindung beliebige LLM-Anfragen auslösen kann. Befehlsausführung auf dem Host hängt davon ab, ob die Anfrage ein konfiguriertes Werkzeug zur Befehlsausführung nutzen kann; sie folgt nicht automatisch aus der fehlenden Headerprüfung. Der CNA nennt Versionen vor 0.35.0 als betroffen, während die Paketmetadaten des GitHub-Hinweises 0.23.0 nennen. Aktualisieren Sie auf 0.35.0 oder neuer und prüfen Sie die installierte Version.
Schritt-für-Schritt Angriffsablauf
Der Proxy besitzt Upstream-Berechtigungen
Ein Headroom-Prozess kann einen OpenAI-Schlüssel in OPENAI_API_KEY halten; der Browserclient muss den Schlüssel nicht selbst senden.
Ein Browser öffnet eine nicht vertrauenswürdige Seite
Kann der Browser den Headroom-WebSocket-Endpunkt erreichen, kann das Seitenskript eine Verbindung versuchen. Der Browser setzt den Seitenursprung in den Handshake.
Der verwundbare Handler akzeptiert ohne Ursprungspolitik
Im betroffenen Handler erreicht die Anfrage websocket.accept(), ohne vorher einen nicht vertrauenswürdigen Origin abzulehnen. Die Same-Origin-Policy ist keine serverseitige WebSocket-Autorisierung.
Der Proxy leitet eine authentifizierte Anfrage weiter
Headroom kann einen fehlenden Upstream-Authorization-Header aus der Umgebung ergänzen. Die Angreiferseite kann dann Anfragen mit den Upstream-Rechten des Proxys auslösen; die Folgen hängen von Werkzeugen, Zugangsdaten, Netzwerkerreichbarkeit und Benutzerinteraktion ab.
Die Korrektur lehnt unzulässige Ursprünge vor dem Routing ab
Der Upstream-Patch prüft den Ursprung vor Annahme und Weiterleitung der Sitzung. Browserursprünge sind standardmäßig auf Loopback begrenzt, erlaubte Ursprünge können konfiguriert werden, und unzulässige Verbindungen werden mit Code 1008 geschlossen.
Quellcode: Verwundbar vs. Sicher
Der Hinweis nennt handle_openai_responses_ws() und die fehlende Prüfung vor websocket.accept(). Commit c632023 fügt _is_allowed_websocket_origin() hinzu und lehnt unzulässige Ursprünge vor dem Routing ab. Native Clients ohne Origin bleiben kompatibel, Browserursprünge sind standardmäßig auf Loopback begrenzt und explizite Ursprünge lassen sich über HEADROOM_WS_ORIGINS oder HEADROOM_CORS_ORIGINS festlegen. Dieses kompakte Paar zeigt die geänderte Vertrauensgrenze; Hilfsfunktionen sind nicht vollständig enthalten. Upstream-Regressionstests decken fehlenden Origin, Loopback, entfernte und fehlerhafte Ursprünge sowie explizite Konfiguration ab.
Quelltextauszug: headroom/proxy/handlers/openai.py
async def handle_openai_responses_ws(self, websocket: WebSocket) -> None:
# Verwundbares Muster: Die Browsersitzung vor der Prüfung des Ursprungs akzeptieren.
await websocket.accept()
await self._relay_responses_session(websocket)
async def handle_openai_responses_ws(self, websocket: WebSocket) -> None:
ws_headers = dict(websocket.headers)
if not _is_allowed_websocket_origin(ws_headers):
logger.warning(
"event=websocket_origin_not_allowed origin=%r",
_header_get(ws_headers, "origin"),
)
await websocket.close(code=1008, reason="origin not allowed")
return
# Nur eine richtlinienkonforme Browsersitzung erreicht das Upstream-Routing.
await websocket.accept()
await self._relay_responses_session(websocket)
Checkliste für Engineering & Systemsicherheit
- ✓Aktualisieren Sie Headroom auf 0.35.0 oder neuer und erfassen Sie die installierte Version sowie das bereitgestellte Image, nicht nur die Abhängigkeitsdatei.
- ✓Prüfen Sie den WebSocket-
Origin, bevoraccept()aufgerufen oder eine Nachricht weitergeleitet wird; lehnen Sie nicht lokale Ursprünge ohne ausdrückliche Freigabe ab. - ✓Erlauben Sie nativen Clients ohne
Originnur, wenn ihr Typ unabhängig vertrauenswürdig ist; ein fehlender Browserursprung ist keine Autorisierung. - ✓Verwenden Sie bei einem Proxy mit Zugangsdaten kein
*in der Ursprungsliste; führen Sie genaue vertrauenswürdige Ursprünge auf und testen Sie die Normalisierung von Standardports. - ✓Binden Sie einen lokalen Entwicklungsproxy nach Möglichkeit an Loopback und setzen Sie Authentifizierung oder Netzwerkkontrollen ein, wenn andere Hosts ihn erreichen können.
- ✓Nutzen Sie nach Möglichkeit eingeschränkt gültige Upstream-Schlüssel; stellen Sie Shell oder andere leistungsstarke Werkzeuge nicht für Anfragen bereit, die die Browsergrenze überschreiten.
- ✓Ergänzen Sie Tests, die einen entfernten Origin vor dem Upstream-Routing mit Richtlinienfehler schließen und zugleich Loopback, konfigurierte Ursprünge und genehmigte native Clients prüfen.
- ✓Befehlsausführung hängt von konfigurierten Werkzeugen ab; der Origin-Fehler allein bedeutet keine automatische Host-RCE.