Voltar
2026/10/26
HTTP2Shell (CVE-2026-111497): atualizar um binário não corrige os processos em execução
A falha do Brotli por trás do HTTP2Shell atinge Node.js, Bun e Python. Como medir a exposição real e reiniciar agentes de IA com segurança.
Em 21 de outubro de 2026, o Node.js publicou correções para a CVE-2026-111497, uma escrita fora dos limites no decodificador Brotli do Google. Nos dias seguintes surgiram avisos para Bun, para os pacotes Python brotli e brotlicffi, para Envoy e para Istio, e a imprensa especializada batizou a falha de Node2Shell e, mais tarde, de HTTP2Shell. Apesar do apelido, não se trata de um bug no protocolo HTTP/2. É um bug de descompressão, relevante onde quer que um software decodifique dados Brotli que um atacante possa influenciar.
Este artigo expõe o que está verificado, o que é apenas possível e como verificar os seus próprios sistemas. Também aborda uma lição da nossa própria resposta: instalar um binário corrigido não corrige um processo que continua executando o antigo. No nosso ambiente, sessões do Claude Code de longa duração mantiveram os seus runtimes embutidos antigos depois de o Claude Code instalado ter sido atualizado.
Pontos principais
- Afetado: Brotli upstream de 1.0.3 a 1.2.0. Corrigido: 1.0.10, 1.1.1 e 1.2.1. Produtos que incluem o Brotli precisam da sua própria versão corrigida.
- A exposição exige um caminho real: dados Brotli influenciados por um atacante chegando a um decodificador vulnerável. O nome de um produto ou o acesso à rede, por si sós, não são prova.
- Verifique os processos em execução, não apenas os pacotes instalados. Um processo mantém o runtime com que foi iniciado até ser reiniciado.
- Reinicie os agentes de IA com estado um de cada vez, transferindo antes os seus eventos, aprovações e estado de trabalho.
1. O que é a vulnerabilidade
Quando o decodificador encontrava uma troca de bloco inválida, informava “need more input” (é preciso mais entrada) em vez de um erro de formato permanente. Um chamador em streaming continuava então a enviar bytes, e o decodificador acrescentava-os a um buffer interno de oito bytes, escrevendo para além do seu fim. O aviso do Node.js afirma que um atacante capaz de fornecer dados Brotli que uma aplicação descomprime com node:zlib “pode corromper a memória do processo, o que pode levar a uma falha, à divulgação da memória do processo ou à execução remota de código”.
As classificações de gravidade variam conforme a fonte. O Node.js classifica-a como High (alta). O aviso do GitHub para os pacotes Python e o aviso do Envoy classificam-na como Critical (crítica), com pontuação CVSS 4.0 de 9.2. O Ubuntu lista-a atualmente com prioridade Medium (média). Em 26 de outubro, a avaliação da CISA no registro da CVE indica a exploração como “none” (nenhuma), e a CVE não consta do catálogo Known Exploited Vulnerabilities da CISA. Ainda assim, o aviso do Node.js aponta a execução remota de código como resultado possível, por isso não trate a ausência de ataques reportados como motivo para esperar.
2. Pré-requisitos: quando você está realmente exposto
As três condições têm de se verificar:
- Um decodificador vulnerável está carregado no processo: uma biblioteca Brotli incluída ou do sistema, na faixa afetada, sem correção nem backport.
- Algo o chama: descompressão explícita ou decodificação automática de
Content-Encoding: br. - A entrada pode ser influenciada por um atacante: respostas de URLs arbitrárias, arquivos enviados, corpos de requisições recebidas ou tráfego HTTP simples numa rede hostil.
A decodificação automática é o caminho que as equipes mais deixam escapar. O aviso do Bun observa que o fetch envia Accept-Encoding: br por padrão e decodifica a resposta, pelo que qualquer programa Bun que acesse URLs não confiáveis tem um caminho. Em Python, assim que brotli ou brotlicffi está instalado, o urllib3 decodifica automaticamente as respostas com Content-Encoding: br, e o requests também anuncia br nas suas requisições. Isto acontece mesmo que o seu próprio código nunca mencione o Brotli. Envoy e Istio só ficam expostos quando um descompressor Brotli está configurado.
3. Afetado confirmado versus apenas possível
Situação em 26 de outubro de 2026. Consulte os avisos indicados, porque a situação evolui rapidamente.
| Componente | Situação | Corrigido em |
|---|---|---|
| Brotli upstream (C) | Confirmado: 1.0.3 a 1.2.0 | 1.0.10, 1.1.1, 1.2.1 |
| Node.js 22, 24, 26 | Confirmado | 22.23.4, 24.22.1, 26.12.1 |
| Node.js 20 e anteriores (fim de vida) | Não avaliado; o Node.js considera as linhas em fim de vida sempre afetadas | Migrar para uma linha suportada |
| Bun (incluindo executáveis compilados) | Confirmado: 1.0.21 a 1.4.3 | 1.4.4, e recompilar as aplicações compiladas |
| Python brotli / brotlicffi | Confirmado: a partir de 1.0.3 | 1.2.1 / 1.2.1.0 |
| Envoy (descompressor Brotli configurado) | Confirmado | 1.40.0, 1.39.3, 1.38.6, 1.37.8 (1.36.12 no ramo 1.36, sem suporte) |
| Istio (descompressão Brotli ativada) | Confirmado | 1.31.2, 1.30.6, 1.29.9 (a última versão 1.29) |
| Pacote brotli do Ubuntu | Em avaliação (todas as versões) | Ainda sem pacote corrigido |
| Pacote nodejs do Ubuntu | Vulnerável no 20.04 (Brotli incluído). A partir do 22.04 usa o Brotli do sistema, portanto segue a linha acima | Ver o rastreador do Ubuntu |
| Pacote brotli do Debian | Corrigido em bookworm e trixie; forky ainda não | 1.0.9-2+deb12u1, 1.1.0-2+deb13u1 |
| Chrome, Electron e aplicações Electron | Desconhecido: nenhuma declaração do fornecedor encontrada | Acompanhar as notas de versão do fornecedor |
Sobre a última linha: o Chrome e o Electron trazem as suas próprias cópias do Brotli, e uma aplicação Electron também embute um runtime Node.js. No momento em que escrevemos, as versões estáveis mais recentes do Electron (45.0.0, 44.9.3 e 43.8.3, todas de 21 de outubro) indicam o Node.js 24.22.0, e não o 24.22.1, e as suas notas não mencionam esta CVE. As pré-versões do Electron de 23 de outubro trazem o Node.js 24.22.1, pelo que uma correção estável parece provável, mas ainda não foi publicada. Isso torna uma aplicação desktop construída sobre Electron possivelmente exposta, não vulnerável confirmada. O mesmo vale para clientes de chat e ferramentas desktop de IA: consulte a declaração de cada fornecedor antes de considerá-los afetados ou seguros.
Mais uma armadilha: a versão reportada de uma biblioteca não é prova em nenhum sentido. Um Node.js 22.23.4 corrigido continua a reportar process.versions.brotli como 1.1.0, porque a correção foi aplicada por backport. As distribuições fazem o mesmo. Avalie pela versão corrigida do produto ou pelo estado de segurança da distribuição, não pela string de versão do Brotli.
4. O que encontramos no nosso próprio ambiente
Fizemos um inventário apenas de leitura antes de alterar qualquer coisa. Eis o que observamos, de forma anonimizada, mantendo as constatações confirmadas separadas do risco que não conseguimos verificar.
Observações confirmadas
- O Claude Code instalado já tinha sido atualizado, mas uma dúzia de sessões de longa duração ainda executava builds mais antigas, iniciadas semanas antes. Nunca tinham sido reiniciadas.
- A nossa primeira contagem deixou escapar três delas. Executavam sob um processo auxiliar diferente, por isso uma pesquisa pela linha de comando não as encontrou. A pesquisa pelo executável encontrou-as.
- Os arquivos das builds antigas já tinham sido apagados do disco pelo atualizador, pelo que não foi possível ler a versão do Bun embutida nesses processos.
- Uma instalação remanescente, via gerenciador de pacotes, de uma build mais antiga do Claude Code embutia o Bun 1.4.0. Nada a usava em operação normal, mas um caminho de fallback poderia tê-la usado. Removemo-la depois de demonstrar que nada dependia dela.
- Um runtime Node.js em fim de vida, sem uso, ainda estava instalado num servidor. Removemo-lo da mesma forma.
- A build atual do Claude Code para a qual atualizamos (2.1.310) contém o Bun 1.4.4. Confirmamos isto inspecionando o binário. O changelog da Anthropic não menciona a CVE, por isso verifique a sua própria build da mesma forma.
Não verificado, tratado como risco
- Se as sessões antigas eram de fato vulneráveis. A versão do Bun delas era ilegível. O Bun 1.4.4 corrigido só apareceu por volta de 22 de outubro, depois dessas builds, por isso tratamo-las como afetadas.
- Se um atacante poderia ter alcançado o decodificador através dessas sessões, por exemplo ao acessar uma URL maliciosa. Este caminho é plausível dado o comportamento documentado do
fetchdo Bun, mas não o comprovamos. - Se outros softwares que incluem a sua própria cópia do Brotli são afetados. Onde não existe declaração do fornecedor, acompanhamos o produto em relação às versões do fornecedor, em vez de presumir que é seguro ou vulnerável.
Não encontramos nenhuma evidência de exploração. Também não tratamos isso como prova de segurança: a solução foi eliminar a exposição, não argumentar contra ela.
5. Lista de verificação para detecção e correção
Encontrar as dependências
Procure o Brotli onde ele vem incluído, não apenas onde está instalado como pacote. Verifique os seus SBOMs e imagens de contêiner em busca de Node.js, Bun, pacotes Python, Envoy e Brotli com ligação estática. Verifique as dependências transitivas do Python, porque o Brotli chega muitas vezes como extra opcional.
# Node.js: compare with 22.23.4 / 24.22.1 / 26.12.1
node -p process.version
# Python packages: run once per interpreter and virtual environment
python -m pip list 2>/dev/null | grep -iE '^(brotli|brotlicffi) '
pipdeptree -r -p brotli # what pulled it in
# Debian / Ubuntu system library (then check the distro tracker)
dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\n' 'libbrotli*'
# Container images, with an SBOM scanner such as Syft
syft <image> | grep -iE 'brotli|node|bun'
Encontrar os runtimes embutidos
Os programas compilados com bun build --compile trazem a sua própria cópia do Bun. O aviso do Bun indica que continuam afetados até serem recompilados com o 1.4.4. Atualizar o Bun na máquina de build não altera os binários já implantados.
# The Bun version inside a compiled executable
grep -aoE 'Bun v1\.[0-9]+\.[0-9]+' /path/to/binary | sort -u
Encontrar os processos em execução
Verifique o que está em execução, não o que está instalado. No Linux, um processo cujo executável foi substituído ou removido mostra (deleted). É um forte indício de que ainda executa uma build antiga.
# Processes still running a deleted (replaced) executable (run as root to see all users)
for p in /proc/[0-9]*; do
e=$(readlink "$p/exe" 2>/dev/null) || continue
case "$e" in *"(deleted)") echo "${p#/proc/} $e";; esac
done
# Processes older than the fix
pgrep -af 'node|bun|claude' # then: ps -o pid,lstart,args -p <pid>
No macOS, lsof -p <pid> mostra o executável que um processo carregou. Faça a correspondência pelo executável, não pelo nome do processo, ou deixará escapar processos auxiliares e workers em segundo plano.
Corrigir, recompilar, reimplantar
- Atualize para as versões corrigidas da tabela. Use o pacote corrigido da sua distribuição onde existir um backport.
- Recompile as imagens de contêiner e os executáveis compilados e, em seguida, reimplante-os. Uma imagem base corrigida não serve de nada para uma imagem que você não recompilou.
- Remova runtimes sem uso e instalações remanescentes, depois de comprovar que nenhum serviço, job ou script depende deles. Mantenha uma forma de reverter.
- Onde ainda não existir correção, desative a decodificação Brotli de entradas não confiáveis onde for seguro fazê-lo. No Bun,
fetch(url, { decompress: false })funciona por requisição. Atribua a cada mitigação um responsável e uma data de término.
Reiniciar e verificar
Após reiniciar, verifique o executável e a versão do runtime efetivos do novo processo. Depois verifique o resultado de negócio: filas esvaziadas, jobs agendados concluídos com sucesso, alertas de monitoramento chegando. Um comando de atualização bem-sucedido prova apenas que o comando foi executado.
6. Reiniciar agentes de IA persistentes com segurança
Os agentes de IA de longa duração guardam estado: chamadas de ferramentas pendentes, aprovações, mensagens em fila e reivindicações de trabalho. Reiniciá-los todos de uma vez pode perder esse estado. Esta sequência funcionou para nós:
- Inventarie cada sessão: versão do executável, estado (ociosa, em espera ou ocupada), última atividade, trabalho pendente, aprovações que aguarda ou detém, eventos não confirmados e como será recuperada.
- Tire as aprovações da memória. Uma aprovação que existe apenas na conversa de uma sessão perde-se ao reiniciar. Antes de reiniciar, registre cada aprovação pendente (o que foi aprovado, por quem, para que alteração exata) num local durável, como o ticket ou o pull request. Depois, confirme que a sessão ainda a vê. Em caso de dúvida, peça a aprovação novamente em vez de a presumir.
- Comprove primeiro a substituição. Confirme que as sessões na build corrigida já funcionam e que um observador de eventos independente das sessões antigas está em execução, para que nenhum evento dependa de uma sessão ser reiniciada.
- Reinicie primeiro as sessões ociosas, uma de cada vez. Após cada uma, verifique que o processo antigo desapareceu, que o novo processo executa o executável corrigido, que o histórico da conversa está intacto e que qualquer conexão remota foi restabelecida. Só então passe à seguinte.
- Reinicie por último o responsável mais ocupado, entre tarefas. Peça-lhe que escreva uma nota de passagem, pare o seu observador apenas com zero eventos pendentes e zero não confirmados, reinicie e confirme que o observador retomou a partir da posição guardada sem perder nada.
- Conte com entradas em fila ao reconectar. Uma das nossas sessões reiniciadas recebeu uma mensagem que estava à espera havia dez dias e agiu com base nela. Verifique a caixa de entrada de cada sessão antes de reiniciar e avise o seu responsável.
- Pare e escale se algum passo não conseguir demonstrar que o trabalho foi recuperado. Não recorra a encerrar tudo à força.
Defina “concluído” antes de começar. Concluído significa nenhum processo em execução numa build afetada, cada exceção documentada com um responsável e uma data de nova verificação, e as verificações de negócio aprovadas. “O pacote foi atualizado” não é concluído.
Fontes
- Registro da CVE: CVE-2026-111497
- Versões de segurança do Node.js de outubro de 2026
- Aviso do Bun GHSA-663w-cv8g-jj2p
- Aviso para Python brotli / brotlicffi GHSA-9v8h-qqgm-4m35
- Aviso do Envoy GHSA-3wvj-j6qm-62mr
- Boletim de segurança do Istio ISTIO-SECURITY-2026-007
- Rastreador de CVE do Ubuntu: CVE-2026-111497
- Rastreador de segurança do Debian: CVE-2026-111497
- Versões do Electron
Global
Japan
Korea
China
Taiwan
Vietnam
Thailand
Indonesia
Spain
France
Germany
Egypt
Russia