
Aviso e análise para CVE-2026-111497, uma escrita fora dos limites no decodificador Brotli acessível via descompressão HTTP do Node.js, com causa raiz, diff de correção, regras de detecção e mitigações.
Última verificação: 2026-11-04 (KST). Cada valor foi registrado apenas se confirmado nas fontes listadas em Referências; quando as fontes divergem, todos os valores são apresentados.
c/dec/decode.c) ignora o valor de retorno de erro de uma transição de bloco inválida (block switch), continuando a decodificação em estado corrompido e realizando uma escrita fora dos limites do buffer (Out-of-Bounds Write).Brotli/brotlicffi, Bun, .NET, Envoy, Istio, etc. É necessário haver um caminho de descompressão de dados Content-Encoding: br controlados pelo atacante para ser afetado.| Item | Conteúdo |
|---|---|
| ID CVE | CVE-2026-111497 (GHSA-9v8h-qqgm-4m35) |
| Apelidos | Node2Shell (nomeado pela Imperva), HTTP2Shell, Broccoli2Shell. Apesar do nome, não é uma falha do protocolo HTTP/2 |
| Data de divulgação | 21/10/2026: lançamento de segurança do Node.js e patch do Brotli / 22/10/2026: publicação do registro CVE |
| Descobridores | OpenAI Codex Security (Khai Tran, Sylvie Mayer) |
| Produtos/versões afetados | Google Brotli (libbrotlidec) 1.0.3 a 1.2.0 e produtos que o empacotam/vincularam (ver tabela abaixo) |
| Versões corrigidas | Brotli 1.0.10 / 1.1.1 / 1.2.1, Node.js 22.23.4 / 24.22.1 / 26.12.1, Python Brotli 1.2.1, brotlicffi 1.2.1.0, Bun 1.4.4 |
| CVSS v4.0 (CNA: Google) | 9.2 Crítico — CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
| CVSS v3.1 (NVD) | 9.8 Crítico — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CVSS v3.1 (Red Hat / Amazon Linux) | 8.1 — CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H (reflete requisitos de ataque AT:P e endurecimento da plataforma) |
| Classificação do próprio fornecedor | Node.js: Alta / Red Hat: Importante |
| CWE | CWE-787 Escrita fora dos limites (NVD, Red Hat, Canadian Cyber Centre) / CWE-252 Valor de retorno não verificado (descrição da CISA KEV, citada como causa raiz em algumas análises) |
| Exploração real | Exploração confirmada. Adicionado à CISA KEV em 27/10/2026, prazo para agências federais: 10/11/2026. Operadores de honeypot (Previdian, ELLIO) observaram tentativas de exploração em 26–27/10 |
| Componente | Versões afetadas | Versão corrigida |
|---|---|---|
| Google Brotli (C, libbrotlidec) | 1.0.3 a 1.2.0 | 1.0.10, 1.1.1, 1.2.1 |
| Node.js 26.x (Atual) | anterior a 26.12.1 | 26.12.1 |
| Node.js 24.x (LTS) | anterior a 24.22.1 | 24.22.1 |
| Node.js 22.x (LTS) | anterior a 22.23.4 | 22.23.4 |
| Node.js 25.x / 23.x / 20.x e anteriores | todas as versões (EOL) | Sem correção → migrar para 22/24/26 |
| Bun | 1.4.3 e anteriores | 1.4.4 |
Python Brotli (PyPI) | 1.2.0 e anteriores | 1.2.1 |
Python brotlicffi | anterior a 1.2.1.0 | 1.2.1.0 |
| .NET / PowerShell | consultar aviso do fornecedor | Atualização urgente do .NET da Microsoft (dotnet/announcements#494) |
| Envoy / Istio | consultar aviso do fornecedor | Correções lançadas no início de outubro (sem menção explícita à falha) |
| VMware SDDC Manager (VCF / vSphere Foundation) | consultar aviso da Broadcom | consultar aviso da Broadcom |
Caminhos de exposição indireta: Python requests, urllib3, aiohttp[speedups], httpx descomprimem automaticamente respostas br se Brotli/brotlicffi estiverem instalados. O curl também é afetado quando a opção de descompressão é usada.
| Data | Evento |
|---|---|
| 02-27 | Commit de correção aplicado ao repositório google/brotli (marcado como problema de segurança, não lançado) |
| Início de outubro | Lançamentos de correção do Envoy / Istio distribuídos |
| 10-21 | Lançamento de segurança do Node.js (22.23.4 / 24.22.1 / 26.12.1), lançamentos do Google Brotli 1.0.10 / 1.1.1 / 1.2.1 |
| 10-22 | Registro CVE divulgado, Imperva demonstra execução de código no Node.js 24.22.0 (Linux arm64) |
| 10-23 | Pacotes PyPI corrigidos distribuídos |
| 10-25 | Aviso e atualização do Microsoft .NET |
| 10-26 | ELLIO reporta tráfego de exploração |
| 10-27 | Inclusão no CISA KEV (prazo de ação 11-10) |
⚠️ Alguns artigos de análise escritos entre 24 e 28 de outubro afirmam que "não há ataques reais confirmados e não há inclusão no KEV", mas isso se baseia no momento anterior à inclusão no KEV e difere da situação atual.
BROTLI_FALSEA decodificação Brotli é uma máquina de estados (state machine). O fluxo é composto por unidades de metassbloco (metablock), e dentro de cada metassbloco aparecem instruções que alternam o tipo de bloco (block switch) de literais (literal), comandos de inserção e cópia (insert-and-copy command) e distância (distance).
DecodeBlockTypeAndLength() interpreta a transição de bloco e retorna BROTLI_BOOL. O problema é que BROTLI_FALSE foi usado com dois significados completamente diferentes.
| Significado | Natureza | Tratamento correto |
|---|---|---|
| É necessário mais entrada (needs more input) | Recuperável | Aguardar a próxima entrada e retomar |
| O metabloco tem apenas 1 tipo de bloco, tornando a transição impossível | Erro de formato fatal | Rejeitar o fluxo |
O lado chamador não verificou esse valor de retorno.
DecodeCommandBlockSwitch) é declarado como static void e não preserva o valor de retorno, e o ramo non-safe da macro BROTLI_SAFE apenas chama a função e descarta o resultado. (Análise da SonicWall)DecodeLiteralBlockSwitch), o valor de retorno é completamente descartado. Embora as funções apontadas variem entre as análises, segundo a descrição do patch da distribuição (TuxCare), todos os três decodificadores de transição de bloco — literal, comando e distância — foram modificados para retornar códigos de erro, portanto pode-se considerar que os três caminhos estão relacionados.Como resultado, mesmo que ocorra um erro de formato, o decodificador continua como se a transição tivesse sido bem-sucedida, o contador de comprimento de bloco permanece em 0, e o estado de posição (position) e distância é transportado para o caminho que deveria ter sido rejeitado.
BrotliDecoderState).ProcessCommandsInternal() calcula o destino como copy_dst = &s->ringbuffer[pos] e realiza um armazenamento vetorial de 16 bytes com memmove16. Como pos não está mais limitado ao intervalo do ring buffer, ocorre uma escrita fora da área alocada.pos, isso se torna uma primitiva write-what-where.