Vulnerabilidade do Node.js: patch do Node2Shell e como verificar a versão do Node.js (WordPress)

Aviso de afiliados v3.1
Aviso de afiliados v3.2 (somente celular)
Ambiente de teste Família RHELAlmaLinux 9.8Nginx + Apache · WordPress 7.1.3Verificado em 2026-10-23

Node2Shell é o apelido da CVE-2026-111497, uma vulnerabilidade do Node.js cujo patch foi publicado em 21 de outubro de 2026; o título oficial descreve uma falha de escrita fora dos limites no decodificador Brotli do Google. Como descompactar dados Brotli manipulados pode levar à execução remota de código, o primeiro passo é verificar as versões do Node.js, do Bun e da libbrotli do seu servidor e atualizá-las para as versões corrigidas.

Em um servidor Nginx + Apache com WordPress 7.1.3, verifiquei quais pacotes usam o decodificador Brotli e por qual caminho as requisições remotas do WordPress passam pela libbrotli.

1️⃣ A vulnerabilidade do Node.js Node2Shell: como a falha funciona e o que ela afeta

O nome Node2Shell é um apelido dado pela equipe de pesquisa da empresa de segurança Imperva em um artigo de 22 de outubro. O título do aviso do nodejs.org é [Brotli decoder out-of-bounds write permits remote code execution]. A falha está no código-fonte do decodificador Brotli do Google embutido no Node.js (c/dec/decode.c), então corrigir o código da sua aplicação não a bloqueia.

Segundo o registro do NVD, o decodificador do Google Brotli 1.0.3 a 1.2.0 grava além do fim do buffer ao descompactar um fluxo manipulado e corrompe a memória de estado adjacente do decodificador. Com essa falha, um invasor remoto sem login pode ler o conteúdo da memória do servidor, derrubar o serviço e executar código arbitrário.

Há duas classificações de gravidade. O aviso do nodejs.org atribuiu o nível High, e o Google, que emitiu a CVE, deu nota 9,2 (Critical) pelo CVSS 4.0. Em 23 de outubro, o NVD ainda não tinha concluído sua própria análise, então ainda não há nota do NVD. Os tipos de fraqueza são valor de retorno não verificado (CWE-252) e escrita fora dos limites (CWE-787).

Segundo o aviso de segurança do nodejs.org, todas as linhas com suporte do Node.js (22.x, 24.x e 26.x) são afetadas, e as versões corrigidas são 22.23.4, 24.22.1 e 26.12.1. O mesmo aviso informa que as linhas sem suporte são sempre consideradas afetadas a cada aviso de segurança.

Qualquer programa que use o mesmo decodificador é afetado, mesmo fora do Node.js. Em 21 de outubro, o Google lançou três versões da biblioteca Brotli que corrigem a mesma CVE: 1.0.10, 1.1.1 e 1.2.1. O Bun incluiu a Brotli na lista de correções de segurança do anúncio da 1.4.4 em 22 de outubro, e uma issue do repositório informa que essa versão traz a correção que atualizou a brotli.

destinoVersões afetadasVersão corrigidaFonte
Node.jsTodas as linhas com suporte 22.x · 24.x · 26.x · linhas sem suporte22.23.4 · 24.22.1 · 26.12.1Aviso de segurança do nodejs.org (2026-10-21)
Biblioteca Brotli do Google1.0.3 ~ 1.2.01.0.10 · 1.1.1 · 1.2.1Registro do NVD · versões do google/brotli (2026-10-21)
BunBrotli na lista de correções de segurança do anúncio da 1.4.41.4.4Anúncio do Bun (2026-10-22)
Pacote libbrotli da distribuiçãoPacotes gerados a partir do Brotli 1.0.3 a 1.2.0A versão indicada no aviso de segurança da distribuição (ainda não havia em 2026-10-23)Página de rastreamento de segurança de cada distribuição

O próprio Node.js não descompacta por conta própria os dados Brotli que recebe. Segundo o aviso de segurança da empresa de hospedagem Vercel, os pontos expostos são aqueles em que um app ou uma biblioteca descompacta dados comprimidos vindos de fora. Exemplos são quando o fetch() embutido recebe uma resposta br e quando o Express 5 ou o body-parser 2 descompacta o corpo de uma requisição br; o servidor HTTP padrão, que só recebe, não descompacta.

Até 23 de outubro, nenhuma exploração real foi confirmada. Esta CVE não está no catálogo de vulnerabilidades exploradas conhecidas da CISA (KEV, versão de 21 de outubro). O estágio de exploração que a CISA atribui no registro da CVE mudou em 23 de outubro para [prova de conceito (PoC) pública].

Onde o decodificador fica determina o que você precisa fazer. Os binários oficiais do Node.js trazem o decodificador embutido no executável, e também há builds que usam a libbrotli do sistema, como o pacote nodejs do Debian. As distribuições Linux instalam o mesmo código-fonte como o pacote libbrotli, que programas como o curl usam em comum.

2️⃣ Sites WordPress e PHP também são afetados: o caminho em que as requisições remotas descompactam respostas com a libbrotli

Mesmo um servidor WordPress sem Node.js tem o mesmo decodificador instalado como o pacote libbrotli. Até 23 de outubro, WordPress, curl e PHP não tinham feito nenhuma menção oficial a esta CVE, e ela também não está na lista oficial de vulnerabilidades do curl. Por isso, esta seção só confirma a estrutura com o código do núcleo, a documentação do curl e medições em um servidor de teste.

No servidor Nginx + Apache medido, cinco pacotes exigiam a biblioteca do decodificador (libbrotlidec), e o que se conecta ao WordPress é a libcurl.

rpm -q --whatrequires 'libbrotlidec.so.1()(64bit)' | sed 's/-[0-9].*//'
freetype
brotli-devel
libjxl
libcurl
libsoup

A libcurl exige a libbrotli para descompactar respostas HTTP comprimidas. Segundo a documentação oficial do curl, a libcurl compilada com a biblioteca brotli descompacta automaticamente as respostas cujo Content-Encoding é br. A extensão curl do PHP chama essa libcurl diretamente.

ldd /usr/lib64/libcurl.so.4 | grep brotli
    libbrotlidec.so.1 => /lib64/libbrotlidec.so.1 (0x00007f32803ed000)
    libbrotlicommon.so.1 => /lib64/libbrotlicommon.so.1 (0x00007f327f858000)
php -i | grep BROTLI
BROTLI => Yes

A versão da libcurl que o WordPress usa aparece na linha [Versão do cURL] quando você expande a seção [Servidor] na aba [Informação] de [Ferramentas › Diagnóstico] no painel administrativo. Essa linha não mostra se há suporte a brotli, então verifique com comandos do servidor como acima.

Tela da aba Informação do Diagnóstico: menu à esquerda Ferramentas › Diagnóstico e as linhas Arquitetura do servidor, Servidor web, Versão do PHP, PHP SAPI e Versão do cURL da seção Servidor — verificação, na linha Versão do cURL, da versão da libcurl, o caminho do lado do WordPress da vulnerabilidade do Node.js Node2Shell (WordPress 7.1.3)

A linha [Versão do cURL] da imagem mostra a versão da libcurl junto com a biblioteca SSL com que ela foi compilada. Segundo a documentação do curl, o br é suportado a partir da 7.57.0; se esse valor for menor, a libcurl não consegue descompactar respostas br. Se for igual ou maior, verifique com comandos do servidor se o brotli entrou na compilação.

Quando a biblioteca Requests do núcleo do WordPress faz uma requisição a uma URL externa, ela define o valor [CURLOPT_ENCODING] do handle do curl como uma string vazia. Segundo a documentação do curl, uma string vazia significa aceitar todos os métodos de compressão suportados por aquela libcurl. Por isso, se o outro servidor enviar uma resposta comprimida com br, a libbrotli do servidor WordPress a descompacta.

grep -n CURLOPT_ENCODING wp-includes/Requests/src/Transport/Curl.php
110:            curl_setopt($this->handle, CURLOPT_ENCODING, '');
212:            curl_setopt($this->handle, CURLOPT_ENCODING, 'none');

A linha 110 é o valor padrão de todas as requisições, e a linha 212 só é executada quando uma requisição que falhou ao descompactar é reenviada sem compressão. Não há como atingir isso diretamente de fora: primeiro seria preciso tomar um servidor de onde o WordPress recebe respostas, como nas verificações de atualização do núcleo e dos plugins, no oEmbed ou nos feeds RSS.

🧩 Fluxo do ataque Node2Shell
Diagrama explicativo
①Dados comprimidos vindos de foraUm corpo de requisição comprimido com br ou a resposta de outro servidor
②O app descompacta com o decodificador BrotliNode.js fetch() · Express 5 · Bun fetch() · WordPress via libcurl → libbrotli
③Falha do decodificador BrotliUm fluxo manipulado grava além do fim do bufferCVE-2026-111497
④Execução de código no servidorVazamento de memória · interrupção do serviço · tomada do servidor
✅ As versões corrigidas bloqueiam este fluxoNode.js 22.23.4 · 24.22.1 · 26.12.1Bun 1.4.4Brotli 1.0.10 · 1.1.1 · 1.2.1

O fluxo começa com dados comprimidos com br vindos de fora. A falha é acionada na etapa em que o fetch() do Node.js, o Express 5, o fetch() do Bun ou a libbrotli chamada pela libcurl do WordPress descompacta esses dados. O resultado leva à execução de código no servidor. As versões corrigidas bloqueiam esse fluxo, então o que você precisa fazer é trocar o decodificador por uma versão corrigida.

O mod_brotli do Apache vincula só a biblioteca do codificador (libbrotlienc), que comprime as respostas, então uma configuração que ativa a compressão com esse módulo não fica no caminho da falha do decodificador.

ldd /usr/lib64/httpd/modules/mod_brotli.so | grep brotli
    libbrotlienc.so.1 => /lib64/libbrotlienc.so.1 (0x00007f34b4b79000)
    libbrotlicommon.so.1 => /lib64/libbrotlicommon.so.1 (0x00007f34b4a79000)

3️⃣ Verificar a versão do Node.js: se o servidor tem Node.js, Bun e libbrotli, e em qual versão

Comece levantando o que está instalado no servidor. No Node.js, veja a versão com [node -v]; se o valor for menor que 22.23.4, 24.22.1 ou 26.12.1, conforme a linha, ele é afetado.

Seu ambienteComando de verificaçãoO que é corrigido
Instalador do nodejs.org · nvm · imagem oficial do Docker[node -v]O próprio Node.js (22.23.4 · 24.22.1 · 26.12.1)
nodejs da distribuição · linha libbrotli no ldd[ldd $(command -v node)]Pacote libbrotli
nodejs da distribuição · resultado do ldd 0[ldd $(command -v node)]Pacote nodejs (após o aviso de segurança da distribuição)
Node.js Selector da hospedagem compartilhada (CloudLinux alt-nodejs)Aviso do provedor · número de release do pacotePacote distribuído pelo provedor + reinício do app
Bun[bun --version]Bun 1.4.4 ou superior
Sem Node.js (só WordPress)Verificar a libcurl com [ldd]Pacote libbrotli + reinício do php-fpm · até lá, medida temporária
Hospedagem gerenciadaAviso do provedor · consulta ao suportePacotes que o provedor atualiza

No PC (Windows ou macOS), reinstale com o instalador da versão corrigida do nodejs.org; no nvm, veja a versão com [nvm ls] e reinstale pelo número da linha, como em [nvm install 24]. As tags 22, 24 e 26 da imagem oficial node do Docker foram refeitas com as versões corrigidas em 22 de outubro, então baixe a imagem de novo, faça o build e publique. O aviso da Vercel também recomenda atualizar para as versões corrigidas as imagens de contêiner que você mesmo gera, os ambientes de CI e os ambientes de desenvolvimento locais.

Em um servidor onde você instalou o Node.js por um stream do dnf module, o [node -v] mostra uma versão da linha desse stream; mesmo que a linha seja a mesma, é preciso atualizar se os últimos dígitos não chegarem à versão corrigida.

node -v
v24.xx.x

Use o [ldd] para verificar se o Node.js usa a libbrotli do sistema ou o decodificador embutido. Se a saída tiver uma linha libbrotlidec, o build usa a biblioteca compartilhada; se der 0, como abaixo, o decodificador é embutido e só atualizando o próprio Node.js a falha é corrigida.

ldd $(command -v node) | grep -c brotli
0

No Bun, verifique a versão com [bun --version] e atualize se for menor que 1.4.4.

Nos sistemas RPM, veja a versão do pacote libbrotli com [rpm -q libbrotli]. Os números de versão dos pacotes são atribuídos pela distribuição, então não os compare diretamente com os números de versão do Google, e sim com a versão que o aviso de segurança da distribuição lançar para este número de CVE.

rpm -q libbrotli
libbrotli-1.0.x-x.el9_x.x86_64

Verifique se a distribuição publicou um aviso com [dnf updateinfo info --cve CVE-2026-111497]. Se a saída estiver vazia, esse repositório ainda não tem aviso para esta CVE.

dnf updateinfo info --cve CVE-2026-111497

Um pacote que só incorpora a correção mantendo o número de versão deixa o número da CVE no registro de alterações. Por isso, verifique com [rpm -q --changelog libbrotli | grep CVE-2026-111497]; se aparecer uma linha, o pacote está corrigido.

rpm -q --changelog libbrotli | grep CVE-2026-111497

Até 23 de outubro, os pacotes libbrotli do Debian, Ubuntu, Red Hat e AlmaLinux ainda não tinham versão corrigida para esta CVE. O Alpine lançou versão corrigida só para o pacote nodejs; a fonte é a página de rastreamento de segurança de cada distribuição. Por isso, por enquanto a ordem é acompanhar o aviso de segurança da distribuição e atualizar quando ele sair.

No Debian e no Ubuntu o pacote se chama libbrotli1, e verifiquei os mesmos itens em um servidor de teste Debian 12 de uma hospedagem gerenciada. Nesse servidor também a libcurl vinculava a libbrotlidec e a extensão curl do PHP suportava brotli. O registro de alterações é visto com [zcat /usr/share/doc/libbrotli1/changelog.Debian.gz | grep CVE-2026-111497].

dpkg -l libbrotli1 | tail -1
ii  libbrotli1:amd64 1.1.0-2+0~20240305.8+debian12~1.gbp62df71 amd64        library implementing brotli encoder and decoder (shared libraries)
ldd /usr/lib/x86_64-linux-gnu/libcurl.so.4 | grep brotli
    libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007fa2baac6000)
    libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007fa2b9cb9000)

4️⃣ Atualizar o Node.js: subir para a versão corrigida e verificar de novo

Na hospedagem gerenciada e na compartilhada, o provedor atualiza os pacotes do servidor, então confirme pelos avisos ou pelo suporte do provedor se o Node.js e a libbrotli já receberam o patch. Se você administra o servidor, atualize o Node.js para a versão corrigida do aviso do nodejs.org e o Bun para a 1.4.4 ou superior com [bun upgrade].

O Node.js instalado por um stream de módulo da distribuição é atualizado com algo como [dnf upgrade nodejs] depois que a versão corrigida chegar a esse repositório. Em um servidor onde você baixou e instalou o Node.js direto do nodejs.org, troque pela versão corrigida do mesmo lugar. As linhas sem suporte não recebem versão corrigida, então passe para uma linha com suporte: 22, 24 ou 26.

O Node.js Selector da hospedagem compartilhada (CloudLinux alt-nodejs) traz uma cópia própria da brotli, então atualizar a libbrotli do sistema não resolve. Segundo o aviso da CloudLinux, o novo binário só passa a rodar depois que o pacote distribuído pelo provedor é instalado e o app é reiniciado. O mesmo aviso informa que nas versões sem suporte o valor de [node --version] não muda, por isso a verificação é feita pelo número de release do pacote.

No pacote libbrotli, quando o aviso de segurança da distribuição sair, atualize o pacote e reinicie os processos que carregaram a biblioteca na memória para que passem a usar a nova biblioteca. Bibliotecas compartilhadas são lidas quando o processo inicia, então em um servidor WordPress o reinício do php-fpm faz parte da mesma etapa.

Depois de atualizar, verifique se o [node -v] mostra a versão corrigida ou mais recente e se o [rpm -q libbrotli] mostra a versão do aviso da distribuição. Confira se o número da CVE entrou no registro de alterações com [rpm -q --changelog libbrotli | grep CVE-2026-111497]. Se você reiniciou o php-fpm, verifique também o status do serviço e a resposta do site.

systemctl is-active php-fpm
active
curl -s -o /dev/null -w '%{http_code}\n' 'https://example.com/?r=1'
200

5️⃣ Medida temporária antes do patch: desativar a descompactação br nas requisições remotas do WordPress

A página da CVE da Red Hat recomenda configurar os apps para não aceitar, ou não descompactar automaticamente, compressão br vinda de fontes não confiáveis.

Mesmo antes de saírem os pacotes corrigidos, você já pode bloquear o caminho do lado do WordPress. O WordPress oferece o hook [http_api_curl], que passa o handle do curl em cada requisição remota. Definindo ali [CURLOPT_ENCODING] como null, a descompactação automática da libcurl é desativada.

Colocando o arquivo abaixo na pasta [wp-content/mu-plugins/], ele vale para todas as requisições remotas; o nome do arquivo é só um exemplo. Para desfazer, basta apagar este arquivo.

<?php
// no-brotli-decode.php — WordPress remoto nas requisições libcurl Automático descompactação Desligado(libbrotli patch versão lançada até)
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}
add_action( 'http_api_curl', function ( $handle ) {
    curl_setopt( $handle, CURLOPT_ENCODING, null );
}, 99 );

É fácil pensar que limitar [CURLOPT_ENCODING] a [gzip, deflate] deixa o br de fora. Esse valor só tira o br do cabeçalho Accept-Encoding da requisição; se o outro servidor responder com br, a libcurl descompacta o que receber mesmo assim. No site de teste, ao buscar httpbin.org/brotli com esse mesmo valor, a resposta com Content-Encoding br foi descompactada e pôde ser lida normalmente.

Segundo a documentação do curl, null é o único valor que desativa a descompactação automática; com null, o cabeçalho Accept-Encoding não é enviado e o corpo recebido também não é descompactado. As respostas gzip e deflate são descompactadas pela própria biblioteca Requests do WordPress e continuam legíveis; só as respostas br ficam sem descompactar.

Esse hook é o que o WordPress conectou ao ponto [curl.before_send], que o Requests chama logo antes de executar o curl. Ele é chamado na linha 174 do Curl.php e o curl é executado na linha 205, então o valor de string vazia que o núcleo colocou na linha 110 é sobrescrito nesse intervalo.

Verifique se funcionou com o arquivo de teste abaixo. O httpbin.org é um endereço de teste que devolve os cabeçalhos da requisição recebida e também respostas comprimidas com br e gzip, então dá para ver de uma vez o que o WordPress envia e o que ele descompacta.

<?php
// br-check.php — WordPress remoto requisição qual compressão envia se descompacta Verificar(httpbin.org teste Endereço)
$h = json_decode( wp_remote_retrieve_body( wp_remote_get( 'https://httpbin.org/headers' ) ), true );
echo 'Accept-Encoding: ', isset( $h['headers']['Accept-Encoding'] ) ? $h['headers']['Accept-Encoding'] : '(none)', PHP_EOL;
foreach ( array( 'brotli', 'gzip' ) as $p ) {
    $r = wp_remote_get( 'https://httpbin.org/' . $p );
    $readable = strpos( wp_remote_retrieve_body( $r ), ': true' ) !== false;
    echo $p, ': Content-Encoding=', wp_remote_retrieve_header( $r, 'content-encoding' ), ' / ', strlen( wp_remote_retrieve_body( $r ) ), ' bytes / ', ( $readable ? 'readable' : 'not decoded' ), PHP_EOL;
}

Antes de adicionar o arquivo, o Accept-Encoding inclui br e a resposta br é descompactada e pode ser lida.

wp eval-file br-check.php
Accept-Encoding: deflate, gzip, br
brotli: Content-Encoding=br / 316 bytes / readable
gzip: Content-Encoding=gzip / 317 bytes / readable

Depois de adicionar o arquivo, o cabeçalho Accept-Encoding some, a resposta br fica sem descompactar e a resposta gzip continua legível.

wp eval-file br-check.php
Accept-Encoding: (none)
brotli: Content-Encoding=br / 199 bytes / not decoded
gzip: Content-Encoding=gzip / 272 bytes / readable

Depois de atualizar para o pacote libbrotli corrigido da distribuição e reiniciar o php-fpm, apague este arquivo para voltar à configuração original.

🔢 FAQ & conteúdo recomendado

As atualizações automáticas do WordPress cobrem só o núcleo, os plugins, os temas e as traduções; a libbrotli e o Node.js são pacotes instalados no servidor, então quem os atualiza é o administrador do servidor ou o provedor de hospedagem. Só depois da atualização e do reinício do php-fpm as requisições remotas do WordPress passam a ser processadas com a nova biblioteca.

Quer um plugin passe pela WordPress HTTP API, quer chame funções curl diretamente, ele passa pela mesma libcurl. O que precisa ser corrigido é o pacote libbrotli do servidor; até sair a versão corrigida, você pode desativar a descompactação automática das requisições remotas do WordPress com a configuração da seção 5️⃣. Segundo a documentação do curl, um código que chama funções curl diretamente sem definir [CURLOPT_ENCODING] não descompacta respostas comprimidas automaticamente. Um código que as chama diretamente e define o valor como string vazia fica fora do hook [http_api_curl], então verifique à parte só as requisições desse plugin.

Os registros da CVE-2026-111497 no NVD e no cve.org (CNA Google) trazem o local da falha (c/dec/decode.c), as versões afetadas e o tipo de fraqueza. As notas das versões v1.2.1, v1.1.1 e v1.0.10 do google/brotli registram a correção. Os detalhes para reproduzir o ataque não foram incluídos neste artigo.

ℹ️ Aviso de afiliados
O conteúdo deste site contém links de afiliados. Quando um visitante compra um produto ou serviço por meio de um desses links, o site recebe uma comissão do vendedor. O valor que o comprador paga (em promoções, ele diminui ↓) não aumenta por causa disso. Preços, descontos e informações de estoque valem para o momento em que o texto foi escrito e podem ter mudado, por isso confirme com o vendedor antes de comprar. Os produtos são escolhidos e avaliados por critérios próprios, e o recebimento de comissão não influencia a ordem de apresentação nem o conteúdo das avaliações.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Demonstre sua humanidade: 6   +   7   =