Vulnerabilità Node.js: la patch Node2Shell e come controllare la versione di Node.js (WordPress)

Informativa sull'affiliazione v3.1
Informativa sull'affiliazione v3.2 (solo mobile)
Ambiente di test Famiglia RHELAlmaLinux 9.8Nginx + Apache · WordPress 7.1.3Verificato il 2026-10-23

Node2Shell è il soprannome di CVE-2026-111497, una vulnerabilità di Node.js la cui patch è stata pubblicata il 21 ottobre 2026; il titolo ufficiale descrive una falla di scrittura fuori dai limiti nel decodificatore Brotli di Google. Poiché decomprimere dati Brotli manipolati può portare all'esecuzione di codice da remoto, la prima cosa da fare è controllare le versioni di Node.js, Bun e libbrotli sul tuo server e aggiornarle alle versioni con la patch.

Su un server Nginx + Apache con WordPress 7.1.3 ho controllato quali pacchetti usano il decodificatore Brotli e attraverso quale percorso le richieste remote di WordPress passano per libbrotli.

1️⃣ La vulnerabilità di Node.js Node2Shell: come funziona la falla e cosa colpisce

Il nome Node2Shell è un soprannome dato dal team di ricerca dell'azienda di sicurezza Imperva in un articolo del 22 ottobre. Il titolo dell'avviso di nodejs.org è [Brotli decoder out-of-bounds write permits remote code execution]. La falla si trova nel codice sorgente del decodificatore Brotli di Google integrato in Node.js (c/dec/decode.c), quindi modificare il codice della tua applicazione non basta a fermarla.

Secondo il record NVD, il decodificatore di Google Brotli da 1.0.3 a 1.2.0 scrive oltre la fine del buffer quando decomprime uno stream manipolato e corrompe la memoria di stato adiacente del decodificatore. Con questa falla, un attaccante remoto senza login può leggere il contenuto della memoria del server, interrompere il servizio ed eseguire codice arbitrario.

Le valutazioni di gravità sono due. L'avviso di nodejs.org ha assegnato il livello High, e Google, che ha emesso la CVE, ha dato 9,2 (Critical) secondo CVSS 4.0. Al 23 ottobre NVD non aveva ancora concluso la propria analisi, quindi non c'è ancora un punteggio NVD. I tipi di debolezza sono un valore di ritorno non verificato (CWE-252) e una scrittura fuori dai limiti (CWE-787).

Secondo l'avviso di sicurezza di nodejs.org, tutti i rami supportati di Node.js (22.x, 24.x e 26.x) sono colpiti, e le versioni con la patch sono 22.23.4, 24.22.1 e 26.12.1. Lo stesso avviso precisa che i rami non più supportati sono sempre considerati colpiti a ogni avviso di sicurezza.

Qualsiasi programma che usa lo stesso decodificatore è colpito, anche fuori da Node.js. Il 21 ottobre Google ha pubblicato tre versioni della libreria Brotli che correggono la stessa CVE: 1.0.10, 1.1.1 e 1.2.1. Bun ha inserito Brotli nell'elenco delle correzioni di sicurezza dell'annuncio della 1.4.4 il 22 ottobre, e una issue del repository precisa che quella versione contiene la correzione che ha aggiornato brotli.

destinazioneVersioni colpiteVersione correttaFonte
Node.jsTutti i rami supportati 22.x · 24.x · 26.x · rami non più supportati22.23.4 · 24.22.1 · 26.12.1Avviso di sicurezza di nodejs.org (2026-10-21)
Libreria Brotli di Google1.0.3 ~ 1.2.01.0.10 · 1.1.1 · 1.2.1Record NVD · release di google/brotli (2026-10-21)
BunBrotli nell'elenco delle correzioni di sicurezza dell'annuncio della 1.4.41.4.4Annuncio di Bun (2026-10-22)
Pacchetto libbrotli della distribuzionePacchetti basati su Brotli da 1.0.3 a 1.2.0La versione indicata nell'avviso di sicurezza della distribuzione (al 2026-10-23 non ancora uscita)Pagina del tracker di sicurezza di ogni distribuzione

Node.js da solo non decomprime i dati Brotli che riceve. Secondo l'avviso di sicurezza dell'azienda di hosting Vercel, i punti esposti sono quelli in cui un'app o una libreria decomprime dati compressi che arrivano dall'esterno. Esempi sono il fetch() integrato quando riceve una risposta br ed Express 5 o body-parser 2 quando decomprimono il corpo di una richiesta br; il server HTTP predefinito, che si limita a ricevere, non decomprime nulla.

Al 23 ottobre non è stato confermato alcuno sfruttamento reale. Questa CVE non è nel catalogo delle vulnerabilità sfruttate note della CISA (KEV, versione del 21 ottobre). Il livello di sfruttamento che la CISA assegna nel record della CVE è passato il 23 ottobre a [proof of concept (PoC) pubblico].

Dove si trova il decodificatore determina cosa devi fare. I binari ufficiali di Node.js integrano il decodificatore nell'eseguibile, ma esistono anche build che usano la libbrotli di sistema, come il pacchetto nodejs di Debian. Le distribuzioni Linux installano lo stesso codice sorgente come pacchetto libbrotli, condiviso da programmi come curl.

2️⃣ Anche i siti WordPress e PHP sono coinvolti: il percorso in cui le richieste remote decomprimono le risposte con libbrotli

Anche su un server WordPress senza Node.js lo stesso decodificatore è installato come pacchetto libbrotli. Al 23 ottobre WordPress, curl e PHP non avevano fatto alcuna dichiarazione ufficiale su questa CVE, che non compare nemmeno nell'elenco ufficiale delle vulnerabilità di curl. Per questo la sezione conferma solo la struttura, con il codice del core, la documentazione di curl e misurazioni su un server di test.

Sul server Nginx + Apache misurato, cinque pacchetti richiedevano la libreria del decodificatore (libbrotlidec), e quello collegato a WordPress è libcurl.

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

libcurl richiede libbrotli per decomprimere le risposte HTTP compresse. Secondo la documentazione ufficiale di curl, una libcurl compilata con la libreria brotli decomprime automaticamente le risposte con Content-Encoding br. L'estensione curl di PHP chiama direttamente quella libcurl.

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

La versione di libcurl usata da WordPress compare nella riga [Versione di cURL] quando nella bacheca apri la sezione [Server] nella scheda [Informazioni] di [Strumenti › Salute del sito]. Quella riga non dice se brotli è supportato, quindi controllalo con i comandi del server come sopra.

Schermata Salute del sito, scheda Informazioni: menu a sinistra Strumenti › Salute del sito e righe Architettura del server, Server web, Versione di PHP, PHP SAPI e Versione di cURL della sezione Server — si controlla nella riga Versione di cURL la versione di libcurl, il percorso lato WordPress della vulnerabilità di Node.js Node2Shell (WordPress 7.1.3)

La riga [Versione di cURL] nell'immagine mostra la versione di libcurl insieme alla libreria SSL con cui è stata compilata. Secondo la documentazione di curl, br è supportato dalla 7.57.0; se questo valore è inferiore, libcurl non riesce a decomprimere le risposte br. Se è uguale o superiore, controlla con i comandi del server se brotli è incluso nella build.

Quando la libreria Requests del core di WordPress invia una richiesta a un URL esterno, imposta il valore [CURLOPT_ENCODING] dell'handle curl su una stringa vuota. Secondo la documentazione di curl, una stringa vuota significa accettare tutti i metodi di compressione supportati da quella libcurl. Quindi, se l'altro server invia una risposta compressa con br, è la libbrotli del server WordPress a decomprimerla.

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');

La riga 110 è il valore predefinito di tutte le richieste, e la riga 212 viene eseguita solo quando una richiesta che non è riuscita a decomprimere viene reinviata senza compressione. Dall'esterno non c'è modo di colpirla direttamente: prima andrebbe compromesso un server da cui WordPress riceve risposte, come nei controlli degli aggiornamenti di core e plugin, in oEmbed o nei feed RSS.

🧩 Flusso dell'attacco Node2Shell
Diagramma esplicativo
①Dati compressi che arrivano dall'esternoUn corpo di richiesta compresso con br o la risposta di un altro server
②L'app li decomprime con il decodificatore BrotliNode.js fetch() · Express 5 · Bun fetch() · WordPress tramite libcurl → libbrotli
③Falla del decodificatore BrotliUno stream manipolato scrive oltre la fine del bufferCVE-2026-111497
④Esecuzione di codice sul serverFuga di memoria · interruzione del servizio · presa del server
✅ Le versioni corrette bloccano questo flussoNode.js 22.23.4 · 24.22.1 · 26.12.1Bun 1.4.4Brotli 1.0.10 · 1.1.1 · 1.2.1

Il flusso inizia con dati compressi con br che arrivano dall'esterno. La falla si attiva nel passaggio in cui il fetch() di Node.js, Express 5, il fetch() di Bun o la libbrotli chiamata dalla libcurl di WordPress li decomprime. Il risultato porta all'esecuzione di codice sul server. Le versioni con la patch bloccano questo flusso, quindi quello che devi fare è sostituire il decodificatore con una versione con la patch.

Il mod_brotli di Apache collega solo la libreria del codificatore (libbrotlienc), che comprime le risposte, quindi una configurazione che attiva la compressione con questo modulo non si trova sul percorso della falla del decodificatore.

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️⃣ Controllare la versione di Node.js: se sul server ci sono Node.js, Bun e libbrotli, e in quale versione

Inizia facendo l'inventario di ciò che è installato sul server. Per Node.js controlla la versione con [node -v]; se il valore è inferiore a 22.23.4, 24.22.1 o 26.12.1 per il suo ramo, è colpito.

Il tuo ambienteComando di verificaCosa viene corretto
Installer di nodejs.org · nvm · immagine ufficiale Docker[node -v]Node.js stesso (22.23.4 · 24.22.1 · 26.12.1)
nodejs della distribuzione · riga libbrotli in ldd[ldd $(command -v node)]Pacchetto libbrotli
nodejs della distribuzione · risultato di ldd 0[ldd $(command -v node)]Pacchetto nodejs (dopo l'avviso di sicurezza della distribuzione)
Node.js Selector dell'hosting condiviso (CloudLinux alt-nodejs)Avviso del provider · numero di release del pacchettoPacchetto distribuito dal provider + riavvio dell'app
Bun[bun --version]Bun 1.4.4 o successivo
Nessun Node.js (solo WordPress)Controllare libcurl con [ldd]Pacchetto libbrotli + riavvio di php-fpm · fino ad allora, misura temporanea
Hosting gestitoAvviso del provider · richiesta al supportoPacchetti aggiornati dal provider

Su un PC (Windows o macOS) reinstalla con l'installer della versione con la patch di nodejs.org; con nvm controlla la versione con [nvm ls] e poi reinstalla per numero di ramo, come [nvm install 24]. I tag 22, 24 e 26 dell'immagine ufficiale node di Docker sono stati ricostruiti con le versioni con la patch il 22 ottobre, quindi scarica di nuovo l'immagine, ricompila e distribuisci. L'avviso di Vercel consiglia anche di aggiornare alle versioni con la patch le immagini container che compili tu, gli ambienti di CI e gli ambienti di sviluppo locali.

Su un server in cui hai installato Node.js tramite uno stream di dnf module, [node -v] mostra una versione del ramo di quello stream; anche se il ramo è lo stesso, devi aggiornare se le ultime cifre non arrivano alla versione con la patch.

node -v
v24.xx.x

Usa [ldd] per controllare se Node.js usa la libbrotli di sistema o il decodificatore integrato. Se l'output contiene una riga libbrotlidec, la build usa la libreria condivisa; se dà 0, come sotto, il decodificatore è integrato e la falla si corregge solo aggiornando Node.js stesso.

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

Per Bun controlla la versione con [bun --version] e aggiorna se è inferiore a 1.4.4.

Sui sistemi RPM controlla la versione del pacchetto libbrotli con [rpm -q libbrotli]. I numeri di versione dei pacchetti li assegna la distribuzione, quindi non confrontarli direttamente con i numeri di release di Google, ma con la versione che l'avviso di sicurezza della distribuzione pubblica per questo numero di CVE.

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

Controlla se la distribuzione ha pubblicato un avviso con [dnf updateinfo info --cve CVE-2026-111497]. Se l'output è vuoto, quel repository non ha ancora un avviso per questa CVE.

dnf updateinfo info --cve CVE-2026-111497

Un pacchetto che incorpora solo la correzione lasciando invariato il numero di versione conserva il numero della CVE nel registro delle modifiche. Per questo si controlla con [rpm -q --changelog libbrotli | grep CVE-2026-111497]; se compare una riga, il pacchetto ha la patch.

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

Al 23 ottobre i pacchetti libbrotli di Debian, Ubuntu, Red Hat e AlmaLinux non hanno ancora una versione con la patch per questa CVE. Alpine ha una versione con la patch solo per il pacchetto nodejs; la fonte è la pagina del tracker di sicurezza di ogni distribuzione. Per ora, quindi, l'ordine è tenere d'occhio l'avviso di sicurezza della distribuzione e aggiornare quando esce.

Su Debian e Ubuntu il pacchetto si chiama libbrotli1, e ho controllato gli stessi punti su un server di test Debian 12 di un hosting gestito. Anche su questo server libcurl collegava libbrotlidec e l'estensione curl di PHP supportava brotli. Il registro delle modifiche si consulta con [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️⃣ Aggiornare Node.js: passare alla versione con la patch e ricontrollare

Con l'hosting gestito e condiviso è il provider ad aggiornare i pacchetti del server, quindi verifica tramite i suoi avvisi o il supporto se Node.js e libbrotli hanno ricevuto la patch. Se gestisci tu il server, aggiorna Node.js alla versione con la patch indicata nell'avviso di nodejs.org e Bun alla 1.4.4 o successiva con [bun upgrade].

Il Node.js installato da uno stream di moduli della distribuzione si aggiorna con un comando come [dnf upgrade nodejs] quando la versione con la patch arriva in quel repository. Su un server in cui hai scaricato e installato Node.js direttamente da nodejs.org, sostituiscilo con la versione con la patch dallo stesso posto. I rami non più supportati non ricevono una versione con la patch, quindi passa a un ramo supportato: 22, 24 o 26.

Il Node.js Selector dell'hosting condiviso (CloudLinux alt-nodejs) ha una propria copia di brotli, quindi aggiornare la libbrotli di sistema non lo corregge. Secondo l'avviso di CloudLinux, il nuovo binario viene eseguito solo dopo il passaggio al pacchetto distribuito dal provider e il riavvio dell'app. Lo stesso avviso precisa che nelle versioni non più supportate il valore di [node --version] resta uguale, quindi si controlla il numero di release del pacchetto.

Con il pacchetto libbrotli, quando esce l'avviso di sicurezza della distribuzione aggiorna il pacchetto e riavvia i processi che hanno la libreria caricata in memoria, così passano alla nuova libreria. Le librerie condivise vengono lette all'avvio di un processo, quindi su un server WordPress il riavvio di php-fpm fa parte dello stesso passaggio.

Dopo l'aggiornamento controlla che [node -v] mostri la versione con la patch o successiva e che [rpm -q libbrotli] mostri la versione dell'avviso della distribuzione. Verifica se il numero della CVE è entrato nel registro delle modifiche con [rpm -q --changelog libbrotli | grep CVE-2026-111497]. Se hai riavviato php-fpm, controlla anche lo stato del servizio e la risposta del sito.

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

5️⃣ Misura temporanea prima della patch: disattivare la decompressione br nelle richieste remote di WordPress

La pagina della CVE di Red Hat consiglia di configurare le app in modo che non accettino, o non decomprimano automaticamente, la compressione br proveniente da fonti non attendibili.

Anche prima che escano i pacchetti con la patch puoi bloccare già ora il percorso lato WordPress. WordPress fornisce l'hook [http_api_curl], che passa l'handle curl a ogni richiesta remota. Impostando lì [CURLOPT_ENCODING] su null, la decompressione automatica di libcurl viene disattivata.

Mettendo il file qui sotto nella cartella [wp-content/mu-plugins/] si applica a tutte le richieste remote; il nome del file è solo un esempio. Per tornare indietro, elimina questo file.

<?php
// no-brotli-decode.php — WordPress remoto nelle richieste libcurl Automatico decompressione Disattivato(libbrotli patch versione uscirà fino a)
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}
add_action( 'http_api_curl', function ( $handle ) {
    curl_setopt( $handle, CURLOPT_ENCODING, null );
}, 99 );

Viene facile pensare che limitando [CURLOPT_ENCODING] a [gzip, deflate] br venga escluso. Quel valore toglie br solo dall'header Accept-Encoding della richiesta: se l'altro server risponde con br, libcurl decomprime comunque ciò che riceve. Sul sito di test, recuperando httpbin.org/brotli con lo stesso valore, la risposta con Content-Encoding br è stata decompressa ed era leggibile così com'era.

Secondo la documentazione di curl, null è l'unico valore che disattiva la decompressione automatica: con null l'header Accept-Encoding non viene inviato e nemmeno il corpo ricevuto viene decompresso. Le risposte gzip e deflate vengono decompresse direttamente dalla libreria Requests di WordPress e restano leggibili; solo le risposte br restano non decompresse.

Questo hook è quello che WordPress ha collegato al punto [curl.before_send], che Requests chiama subito prima di eseguire curl. Viene chiamato alla riga 174 di Curl.php e curl viene eseguito alla riga 205, quindi la stringa vuota che il core ha impostato alla riga 110 viene sovrascritta nel mezzo.

Controlla se funziona con il file di test qui sotto. httpbin.org è un indirizzo di test che restituisce gli header della richiesta ricevuta e anche risposte compresse con br e gzip, così vedi in un colpo solo cosa invia WordPress e cosa decomprime.

<?php
// br-check.php — WordPress remoto richiesta quale compressione invia se decomprime Verifica(httpbin.org test Indirizzo)
$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;
}

Prima di aggiungere il file, Accept-Encoding contiene br e la risposta br viene decompressa ed è leggibile.

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

Dopo aver aggiunto il file, l'header Accept-Encoding scompare, la risposta br resta non decompressa e la risposta gzip è ancora leggibile.

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

Dopo aver aggiornato al pacchetto libbrotli con la patch della distribuzione e riavviato php-fpm, elimina questo file per tornare alla situazione originale.

🔢 FAQ & contenuti consigliati

Gli aggiornamenti automatici di WordPress riguardano solo il core, i plugin, i temi e le traduzioni; libbrotli e Node.js sono pacchetti installati sul server, quindi li aggiorna l'amministratore del server o il provider di hosting. Solo dopo l'aggiornamento e il riavvio di php-fpm le richieste remote di WordPress vengono gestite con la nuova libreria.

Che un plugin passi dalla WordPress HTTP API o chiami direttamente le funzioni curl, passa dalla stessa libcurl. Ciò che va corretto è il pacchetto libbrotli del server; finché non esce la versione con la patch, puoi disattivare la decompressione automatica delle richieste remote di WordPress con l'impostazione della sezione 5️⃣. Secondo la documentazione di curl, il codice che chiama direttamente le funzioni curl senza impostare [CURLOPT_ENCODING] non decomprime automaticamente le risposte compresse. Il codice che le chiama direttamente impostando il valore su una stringa vuota resta fuori dall'hook [http_api_curl], quindi controlla a parte le richieste di quel plugin.

I record di CVE-2026-111497 su NVD e cve.org (CNA Google) riportano la posizione della falla (c/dec/decode.c), le versioni colpite e il tipo di debolezza. Le note di rilascio di google/brotli v1.2.1, v1.1.1 e v1.0.10 riportano la correzione. I dettagli per riprodurre l'attacco non sono stati inclusi in questo articolo.

ℹ️ Informativa sull'affiliazione
I contenuti di questo sito includono link di affiliazione. Se un visitatore acquista un prodotto o un servizio tramite uno di questi link, il sito riceve una commissione dal venditore. In questo processo l'importo pagato dall'acquirente (durante le promozioni l'importo scende↓) non aumenta. Prezzi, sconti e disponibilità indicati si riferiscono al momento della stesura e possono differire da quelli reali: prima di acquistare verifica sempre presso il venditore. I prodotti vengono scelti e valutati secondo criteri propri, e le commissioni non influiscono sull'ordine di presentazione né sul contenuto delle valutazioni.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Dimostra di essere umano: 4   +   9   =