flawopen.com/Teardowns/cve-2026-71416-headroom-websocket-origin-hijacking
CVE-2026-71416: sequestro de origem WebSocket no Headroom
O Headroom não validava Origin no WebSocket; um site visitado podia enviar solicitações LLM pelo proxy acessível. Atualize para 0.35.0+.
Um recepcionista deixa qualquer pessoa entrar em um balcão privado porque não confere o crachá do visitante. O cabeçalho Origin do navegador é esse crachá: o proxy precisa verificá-lo antes de abrir um canal que possa usar a chave de API armazenada.
Conceitos Centrais e Termos
WebSocket- Conexão bidirecional e persistente iniciada por uma solicitação HTTP de upgrade e usada para trocar mensagens nos dois sentidos.
Cabeçalho Origin- Esquema, host e porta enviados pelo navegador para identificar a página que iniciou a solicitação. No handshake WebSocket, o servidor deve aplicar sua própria política de confiança; cabeçalhos CORS não substituem essa verificação.
CSWSH- Cross-Site WebSocket Hijacking: uma página não confiável abre um WebSocket para um serviço acessível que não valida a origem iniciadora.
Credencial ambiente- Segredo já disponível ao processo, como uma chave de API em variável de ambiente, que pode autenticar uma solicitação sem credencial própria do cliente.
CWE-1385- Falta de validação de Origin em WebSockets: o endpoint não verifica se a origem da comunicação é permitida.
Mapeamentos de frameworks
- Referência CWE para a fraqueza descrita neste guia: CWE-1385
- OWASP GenAI 2025 — LLM06:2025 Agência excessiva
Análise de Causa Raiz
O handler WebSocket /v1/responses do Headroom aceitava a conexão do navegador antes de conferir o Origin do handshake. Em seguida, o proxy podia acrescentar OPENAI_API_KEY do próprio ambiente à solicitação upstream. A política de mesma origem do navegador não impede, por si só, que JavaScript inicie um WebSocket para outro host acessível; o navegador normalmente envia Origin, e cabe ao servidor rejeitar origens fora da política. A exploração depende, portanto, de o navegador da vítima alcançar um proxy Headroom vulnerável e de o proxy possuir credenciais ou integrações úteis. O aviso diz que a conexão aceita pode emitir solicitações LLM arbitrárias. A execução de comandos no host depende de a solicitação poder usar uma ferramenta configurada para executar comandos; não decorre automaticamente da falta de validação do cabeçalho. O CNA lista versões anteriores a 0.35.0 como afetadas, enquanto os metadados do aviso GitHub citam 0.23.0. Atualize para 0.35.0 ou posterior e confirme a versão instalada.
Fluxo de Ataque Passo a Paso
O proxy detém autoridade upstream
Um processo Headroom pode ter uma chave OpenAI em OPENAI_API_KEY; o cliente navegador não precisa enviar a chave.
O navegador acessa uma página não confiável
Se conseguir alcançar o endpoint WebSocket do Headroom, o script da página pode tentar uma conexão. O navegador inclui a origem da página no handshake.
O handler vulnerável aceita sem política de origem
No handler afetado, a solicitação chega a websocket.accept() sem rejeitar primeiro um Origin não confiável. A política de mesma origem não é uma verificação de autorização WebSocket no servidor.
O proxy encaminha uma solicitação autenticada
O Headroom pode preencher o cabeçalho Authorization upstream ausente usando o ambiente. A página controlada pelo atacante pode então provocar solicitações com a autoridade do proxy; o impacto depende das ferramentas, credenciais, alcance de rede e interação do usuário.
A correção rejeita origens proibidas antes do roteamento
O patch upstream verifica a origem antes de aceitar e encaminhar a sessão. Por padrão, limita origens de navegador ao loopback, permite origens configuradas e fecha uma conexão proibida com o código 1008.
Código-Fonte: Vulnerável vs. Seguro
O aviso identifica handle_openai_responses_ws() e a ausência de verificação antes de websocket.accept(). O commit c632023 adiciona _is_allowed_websocket_origin() e rejeita uma origem proibida antes do roteamento; preserva clientes nativos sem Origin, limita origens de navegador ao loopback por padrão e permite origens configuradas com HEADROOM_WS_ORIGINS ou HEADROOM_CORS_ORIGINS. Este par compacto destaca a fronteira de confiança alterada; os auxiliares não estão reproduzidos integralmente. Os testes upstream cobrem Origin ausente, loopback, origem remota, valor malformado e configuração explícita.
Trecho de origem: headroom/proxy/handlers/openai.py
async def handle_openai_responses_ws(self, websocket: WebSocket) -> None:
# Formato vulnerável: aceite a sessão do navegador antes de validar a origem.
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
# Somente uma sessão do navegador aprovada pela política chega ao roteamento upstream.
await websocket.accept()
await self._relay_responses_session(websocket)
Lista de Verificação de Segurança para Engenharia
- ✓Atualize o Headroom para 0.35.0 ou posterior e inventarie a versão instalada e a imagem de implantação, não apenas o arquivo de dependências.
- ✓Valide
Origindo WebSocket antes de chamaraccept()ou encaminhar mensagens; negue origens não locais, salvo se estiverem explicitamente permitidas. - ✓Preserve clientes nativos sem
Originsomente quando seu tipo for confiável por outro mecanismo; ausência de origem no navegador não é autorização. - ✓Não use
*na configuração de origens permitidas em um proxy com credenciais; enumere origens confiáveis exatas e teste a normalização de portas padrão. - ✓Quando possível, vincule o proxy local de desenvolvimento ao loopback e exija autenticação ou controles de rede se outros hosts puderem alcançá-lo.
- ✓Use chaves upstream com escopo limitado e curta duração quando disponível; evite expor shell ou ferramentas de alto impacto a solicitações que cruzam a fronteira do navegador.
- ✓Adicione testes que provem que uma origem remota é fechada com violação de política antes do roteamento upstream, mantendo o comportamento esperado para loopback, origens configuradas e clientes nativos aprovados.
- ✓Trate execução de comandos como dependente das ferramentas configuradas; a falha de Origin não é, sozinha, RCE automática no host.