Node.js-kwetsbaarheid: de Node2Shell-patch en je Node.js-versie controleren (WordPress)

Affiliatemelding v3.1
Affiliatemelding v3.2 (mobiel)
Testomgeving RHEL-familieAlmaLinux 9.8Nginx + Apache · WordPress 7.1.3Gecontroleerd op 2026-10-23

Node2Shell is de bijnaam van CVE-2026-111497, een Node.js-kwetsbaarheid waarvoor op 21 oktober 2026 een patch is uitgebracht; de officiële titel beschrijft een out-of-bounds write-lek in de Brotli-decoder van Google. Omdat het uitpakken van gemanipuleerde Brotli-data kan leiden tot het uitvoeren van code op afstand, controleer je eerst de versies van Node.js, Bun en libbrotli op je server en werk je ze bij naar de gepatchte versies.

Op een Nginx + Apache-server met WordPress 7.1.3 heb ik gecontroleerd welke pakketten de Brotli-decoder gebruiken en via welke route externe verzoeken van WordPress langs libbrotli lopen.

1️⃣ De Node.js-kwetsbaarheid Node2Shell: hoe het lek werkt en wat er geraakt wordt

De naam Node2Shell is een bijnaam die het onderzoeksteam van beveiligingsbedrijf Imperva gaf in een onderzoeksartikel van 22 oktober. De titel van het bericht op nodejs.org is [Brotli decoder out-of-bounds write permits remote code execution]. Het lek zit in de broncode van de Google Brotli-decoder die in Node.js is ingebouwd (c/dec/decode.c), dus je houdt het niet tegen door de code van je applicatie aan te passen.

Volgens het NVD-record schrijft de decoder van Google Brotli 1.0.3 tot en met 1.2.0 bij het uitpakken van een gemanipuleerde stream voorbij het einde van een buffer en beschadigt zo het aangrenzende statusgeheugen van de decoder. Via dit lek kan een aanvaller op afstand zonder inloggen servergeheugen uitlezen, de dienst platleggen en willekeurige code uitvoeren.

Er zijn twee ernstbeoordelingen. Het bericht op nodejs.org geeft het niveau High, en Google, dat de CVE uitgaf, gaf volgens CVSS 4.0 een score van 9,2 (Critical). Op 23 oktober had NVD zijn eigen analyse nog niet afgerond, dus er is nog geen NVD-score. De zwakheidstypen zijn een ongecontroleerde returnwaarde (CWE-252) en een out-of-bounds write (CWE-787).

Volgens het beveiligingsbericht op nodejs.org zijn alle ondersteunde Node.js-releaselijnen (22.x, 24.x en 26.x) getroffen, en de gepatchte versies zijn 22.23.4, 24.22.1 en 26.12.1. Hetzelfde bericht vermeldt dat niet meer ondersteunde lijnen bij elk beveiligingsbericht altijd als getroffen gelden.

Elk programma dat dezelfde decoder gebruikt, is getroffen, ook buiten Node.js. Op 21 oktober bracht Google drie versies van de Brotli-bibliotheek uit die dezelfde CVE verhelpen: 1.0.10, 1.1.1 en 1.2.1. Bun zette Brotli op 22 oktober in de lijst met beveiligingsfixes van de aankondiging van 1.4.4, en een issue in de repository vermeldt dat die versie de fix met de brotli-update bevat.

doelGetroffen versiesGecorrigeerde versieBron
Node.jsAlle ondersteunde lijnen 22.x · 24.x · 26.x · niet meer ondersteunde lijnen22.23.4 · 24.22.1 · 26.12.1Beveiligingsbericht van nodejs.org (2026-10-21)
Brotli-bibliotheek van Google1.0.3 ~ 1.2.01.0.10 · 1.1.1 · 1.2.1NVD-record · google/brotli-releases (2026-10-21)
BunBrotli in de lijst met beveiligingsfixes van de aankondiging van 1.4.41.4.4Aankondiging van Bun (2026-10-22)
libbrotli-pakket van de distributiePakketten gebouwd op Brotli 1.0.3 tot en met 1.2.0De versie uit het beveiligingsbericht van de distributie (op 2026-10-23 nog niet uit)Securitytrackerpagina van elke distributie

Node.js zelf pakt ontvangen Brotli-data niet uit eigen beweging uit. Volgens het beveiligingsbericht van hostingbedrijf Vercel zitten de kwetsbare plekken waar een app of bibliotheek gecomprimeerde data van buitenaf uitpakt. Voorbeelden zijn de ingebouwde fetch() die een br-antwoord ontvangt en Express 5 of body-parser 2 die een br-verzoekbody uitpakt; de standaard-HTTP-server, die alleen ontvangt, pakt niets uit.

Op 23 oktober was er geen daadwerkelijk misbruik bevestigd. Deze CVE staat niet in de catalogus van bekende misbruikte kwetsbaarheden van CISA (KEV, versie van 21 oktober). De misbruikstatus die CISA in het CVE-record toekent, werd op 23 oktober gewijzigd in [proof of concept (PoC) openbaar].

Waar de decoder zit, bepaalt wat je moet doen. De officiële binaries van Node.js hebben de decoder in het uitvoerbare bestand ingebouwd, en er zijn ook builds die de libbrotli van het systeem gebruiken, zoals het nodejs-pakket van Debian. Linuxdistributies installeren dezelfde broncode als het pakket libbrotli, dat programma's zoals curl samen gebruiken.

2️⃣ Ook WordPress- en PHP-sites geraakt: de route waarlangs externe verzoeken antwoorden met libbrotli uitpakken

Ook op een WordPress-server zonder Node.js staat dezelfde decoder, geïnstalleerd als het pakket libbrotli. Op 23 oktober hadden WordPress, curl en PHP niets officieels over deze CVE gezegd, en ook in de officiële kwetsbaarhedenlijst van curl staat ze niet. Daarom bevestigt dit hoofdstuk alleen de structuur, met de core-code, de curl-documentatie en metingen op een testserver.

Op de gemeten Nginx + Apache-server vereisten vijf pakketten de decoderbibliotheek (libbrotlidec), en het pakket dat met WordPress verbonden is, is libcurl.

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

libcurl vereist libbrotli om gecomprimeerde HTTP-antwoorden uit te pakken. Volgens de officiële curl-documentatie pakt een libcurl die met de brotli-bibliotheek is gebouwd antwoorden met Content-Encoding br automatisch uit. Die libcurl wordt rechtstreeks aangeroepen door de curl-extensie van PHP.

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

De libcurl-versie die WordPress gebruikt, staat in de regel [cURL versie] als je in het beheerscherm onder [Tools › Sitediagnose] op het tabblad [Informatie] de sectie [Server] openklapt. Of brotli wordt ondersteund, staat niet in die regel, dus controleer je dat zoals hierboven met servercommando's.

Scherm Sitediagnose, tabblad Informatie: linkermenu Tools › Sitediagnose en de regels Serverarchitectuur, Webserver, PHP versie, PHP SAPI en cURL versie in de sectie Server — de libcurl-versie, de WordPress-route van de Node.js-kwetsbaarheid Node2Shell, controleren in de regel cURL versie (WordPress 7.1.3)

De regel [cURL versie] in de afbeelding toont de libcurl-versie samen met de SSL-bibliotheek waarmee die is gebouwd. Volgens de curl-documentatie wordt br vanaf 7.57.0 ondersteund; is deze waarde lager, dan kan libcurl br-antwoorden niet uitpakken. Is ze gelijk of hoger, controleer dan met servercommando's of brotli in de build zit.

Wanneer de Requests-bibliotheek van de WordPress-core een verzoek naar een externe URL stuurt, zet ze de waarde [CURLOPT_ENCODING] van de curl-handle op een lege string. Volgens de curl-documentatie betekent een lege string dat alle compressiemethoden die die libcurl ondersteunt worden geaccepteerd. Stuurt de andere server dus een met br gecomprimeerd antwoord, dan pakt de libbrotli van de WordPress-server dat uit.

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

Regel 110 is de standaard voor elk verzoek, en regel 212 wordt alleen uitgevoerd wanneer een verzoek waarvan het uitpakken mislukte opnieuw zonder compressie wordt verstuurd. Van buitenaf is dit niet rechtstreeks te raken; eerst zou een server waarvan WordPress antwoorden ophaalt moeten worden overgenomen, zoals bij update-checks voor core en plugins, oEmbed of RSS-feeds.

🧩 Verloop van de Node2Shell-aanval
Uitlegdiagram
①Gecomprimeerde data van buitenafEen met br gecomprimeerde verzoekbody of een antwoord van een andere server
②De app pakt ze uit met de Brotli-decoderNode.js fetch() · Express 5 · Bun fetch() · WordPress via libcurl → libbrotli
③Lek in de Brotli-decoderEen gemanipuleerde stream schrijft voorbij het einde van de bufferCVE-2026-111497
④Code-uitvoering op de serverGeheugenlek · uitval van de dienst · overname van de server
✅ De gecorrigeerde versies blokkeren dit verloopNode.js 22.23.4 · 24.22.1 · 26.12.1Bun 1.4.4Brotli 1.0.10 · 1.1.1 · 1.2.1

Het verloop begint met br-gecomprimeerde data van buitenaf. Het lek wordt geraakt in de stap waarin fetch() van Node.js, Express 5, fetch() van Bun of de libbrotli die door de libcurl van WordPress wordt aangeroepen die data uitpakt. Het resultaat leidt tot het uitvoeren van code op de server. De gepatchte versies blokkeren dit verloop, dus wat je moet doen is de decoder vervangen door een gepatchte versie.

Het mod_brotli van Apache koppelt alleen de encoderbibliotheek (libbrotlienc), die antwoorden comprimeert, dus een configuratie die compressie met deze module aanzet, ligt niet op de route van het decoderlek.

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️⃣ Je Node.js-versie controleren: of Node.js, Bun en libbrotli op de server staan en welke versies

Begin met in kaart brengen wat er op de server is geïnstalleerd. Bij Node.js bekijk je de versie met [node -v]; is de waarde lager dan 22.23.4, 24.22.1 of 26.12.1 voor die lijn, dan is hij getroffen.

Jouw omgevingCommando om te controlerenWat er wordt verholpen
Installer van nodejs.org · nvm · officiële Docker-image[node -v]Node.js zelf (22.23.4 · 24.22.1 · 26.12.1)
nodejs van de distributie · libbrotli-regel in ldd[ldd $(command -v node)]libbrotli-pakket
nodejs van de distributie · ldd-resultaat 0[ldd $(command -v node)]nodejs-pakket (na het beveiligingsbericht van de distributie)
Node.js Selector bij gedeelde hosting (CloudLinux alt-nodejs)Bericht van de provider · release-nummer van het pakketDoor de provider uitgerold pakket + app herstarten
Bun[bun --version]Bun 1.4.4 of hoger
Geen Node.js (alleen WordPress)libcurl controleren met [ldd]libbrotli-pakket + php-fpm herstarten · tot dan de tijdelijke maatregel
Managed hostingBericht van de provider · navraagPakketten die de provider bijwerkt

Op een pc (Windows of macOS) installeer je opnieuw met de installer van de gepatchte versie van nodejs.org; met nvm bekijk je de versie met [nvm ls] en installeer je daarna opnieuw op lijnnummer, zoals [nvm install 24]. De tags 22, 24 en 26 van de officiële Docker-image node zijn op 22 oktober opnieuw gebouwd met de gepatchte versies, dus haal de image opnieuw op, bouw opnieuw en rol uit. Het bericht van Vercel raadt ook aan zelfgebouwde container-images, CI-omgevingen en lokale ontwikkelomgevingen naar de gepatchte versies bij te werken.

Op een server waar je Node.js hebt geïnstalleerd via een dnf-modulestream, toont [node -v] een versie uit de lijn van die stream; ook als de lijn klopt, moet je bijwerken wanneer de laatste cijfers onder de gepatchte versie liggen.

node -v
v24.xx.x

Of Node.js de libbrotli van het systeem of zijn ingebouwde decoder gebruikt, controleer je met [ldd]. Staat er een libbrotlidec-regel in de uitvoer, dan gebruikt de build de gedeelde bibliotheek; is het 0, zoals hieronder, dan is de decoder ingebouwd en helpt alleen het bijwerken van Node.js zelf.

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

Bij Bun controleer je de versie met [bun --version] en werk je bij als die lager is dan 1.4.4.

Op RPM-systemen bekijk je de versie van het pakket libbrotli met [rpm -q libbrotli]. Versienummers van pakketten worden door de distributie toegekend, dus vergelijk ze niet rechtstreeks met de releasenummers van Google, maar met de versie die het beveiligingsbericht van de distributie voor dit CVE-nummer uitbrengt.

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

Of de distributie een bericht heeft uitgebracht, controleer je met [dnf updateinfo info --cve CVE-2026-111497]. Is de uitvoer leeg, dan heeft die repository nog geen bericht voor deze CVE.

dnf updateinfo info --cve CVE-2026-111497

Een pakket dat alleen de fix overneemt en het versienummer gelijk laat, laat het CVE-nummer achter in de changelog. Controleer daarom met [rpm -q --changelog libbrotli | grep CVE-2026-111497]; verschijnt er een regel, dan is het pakket gepatcht.

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

Op 23 oktober hadden de libbrotli-pakketten van Debian, Ubuntu, Red Hat en AlmaLinux nog geen gepatchte versie voor deze CVE. Bij Alpine is alleen voor het nodejs-pakket een gepatchte versie uitgekomen; de bron is de securitytrackerpagina van elke distributie. Voorlopig is de volgorde dus: letten op het beveiligingsbericht van de distributie en bijwerken zodra het er is.

Bij Debian en Ubuntu heet het pakket libbrotli1, en ik heb dezelfde punten gecontroleerd op een Debian 12-testserver bij een managed hostingprovider. Ook op deze server koppelde libcurl libbrotlidec en ondersteunde de curl-extensie van PHP brotli. De changelog bekijk je met [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️⃣ Node.js bijwerken: naar de gepatchte versie en opnieuw controleren

Bij managed en gedeelde hosting werkt de provider de serverpakketten bij, dus controleer via de berichten of de support van de provider of Node.js en libbrotli zijn gepatcht. Beheer je de server zelf, werk Node.js dan bij naar de gepatchte versie uit het bericht van nodejs.org en Bun met [bun upgrade] naar 1.4.4 of hoger.

Node.js uit een modulestream van de distributie werk je bij met een commando als [dnf upgrade nodejs] zodra de gepatchte versie in die repository staat. Heb je Node.js rechtstreeks van nodejs.org gedownload en geïnstalleerd, vervang het dan door de gepatchte versie van dezelfde plek. Niet meer ondersteunde lijnen krijgen geen gepatchte versie, dus stap over op een ondersteunde lijn: 22, 24 of 26.

De Node.js Selector bij gedeelde hosting (CloudLinux alt-nodejs) heeft een eigen kopie van brotli, dus het bijwerken van de libbrotli van het systeem verhelpt het niet. Volgens het bericht van CloudLinux draait de nieuwe binary pas als het door de provider uitgerolde pakket er staat en de app opnieuw is gestart. Hetzelfde bericht meldt dat bij niet meer ondersteunde versies de waarde van [node --version] gelijk blijft, zodat je het release-nummer van het pakket controleert.

Bij het pakket libbrotli werk je het pakket bij zodra het beveiligingsbericht van de distributie uit is, en herstart je de processen die de bibliotheek in het geheugen hebben, zodat ze de nieuwe bibliotheek gebruiken. Gedeelde bibliotheken worden ingelezen wanneer een proces start, dus op een WordPress-server hoort het herstarten van php-fpm bij dezelfde stap.

Controleer na het bijwerken of [node -v] minstens de gepatchte versie toont en of [rpm -q libbrotli] de versie uit het bericht van de distributie toont. Of het CVE-nummer in de changelog staat, controleer je met [rpm -q --changelog libbrotli | grep CVE-2026-111497]. Heb je php-fpm herstart, controleer dan ook de status van de dienst en het antwoord van de site.

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

5️⃣ Tijdelijke maatregel vóór de patch: br-uitpakken in externe verzoeken van WordPress uitzetten

De CVE-pagina van Red Hat raadt aan apps zo in te stellen dat ze br-compressie uit onbetrouwbare bronnen niet accepteren of niet automatisch uitpakken.

Ook voordat er gepatchte pakketten zijn, kun je de WordPress-route nu al blokkeren. WordPress biedt de hook [http_api_curl], die bij elk extern verzoek de curl-handle doorgeeft. Zet je daar [CURLOPT_ENCODING] op null, dan staat het automatische uitpakken van libcurl uit.

Zet je het onderstaande bestand in de map [wp-content/mu-plugins/], dan geldt het voor alle externe verzoeken; de bestandsnaam is een voorbeeld. Om het terug te draaien, verwijder je dit bestand.

<?php
// no-brotli-decode.php — WordPress extern in verzoeken libcurl Automatisch uitpakken Uit(libbrotli patch versie verschijnt tot)
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}
add_action( 'http_api_curl', function ( $handle ) {
    curl_setopt( $handle, CURLOPT_ENCODING, null );
}, 99 );

Je zou denken dat br wegvalt als je [CURLOPT_ENCODING] beperkt tot [gzip, deflate]. Die waarde haalt br alleen uit de Accept-Encoding-header van het verzoek; antwoordt de andere server met br, dan pakt libcurl het ontvangen antwoord toch uit. Op de testsite werd httpbin.org/brotli met diezelfde waarde opgehaald, en het antwoord met Content-Encoding br werd gewoon uitgepakt en was leesbaar.

Volgens de curl-documentatie is null de enige waarde die het automatische uitpakken uitzet; met null stuurt libcurl geen Accept-Encoding-header en pakt het de ontvangen body ook niet uit. gzip- en deflate-antwoorden worden door de Requests-bibliotheek van WordPress zelf uitgepakt en blijven leesbaar; alleen br-antwoorden blijven onuitgepakt.

Deze hook heeft WordPress gekoppeld aan het punt [curl.before_send], dat Requests vlak voor het uitvoeren van curl aanroept. Hij wordt aangeroepen op regel 174 van Curl.php en curl draait op regel 205, dus de lege string die de core op regel 110 heeft ingesteld, wordt daartussen overschreven.

Of het werkt, controleer je met het testbestand hieronder. httpbin.org is een testadres dat de ontvangen verzoekheaders terugstuurt en ook met br en gzip gecomprimeerde antwoorden geeft, zodat je in één keer ziet wat WordPress verstuurt en wat het uitpakt.

<?php
// br-check.php — WordPress extern verzoek welke compressie verstuurt of het uitpakt Controleren(httpbin.org test Adres)
$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;
}

Voordat het bestand erin staat, bevat Accept-Encoding br en wordt het br-antwoord uitgepakt en is het leesbaar.

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

Nadat het bestand erin staat, is de Accept-Encoding-header weg, blijft het br-antwoord onuitgepakt en is het gzip-antwoord nog steeds leesbaar.

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

Zodra je het gepatchte libbrotli-pakket van de distributie hebt geïnstalleerd en php-fpm opnieuw hebt gestart, verwijder je dit bestand om terug te gaan naar de oorspronkelijke situatie.

🔢 FAQ & aanbevolen content

De automatische updates van WordPress gaan alleen over de core, plugins, thema's en vertalingen; libbrotli en Node.js zijn pakketten die op de server zijn geïnstalleerd, dus de serverbeheerder of de hostingprovider werkt ze bij. Pas als ze zijn bijgewerkt en php-fpm opnieuw is gestart, worden de externe verzoeken van WordPress met de nieuwe bibliotheek afgehandeld.

Of een plugin nu via de WordPress HTTP API gaat of curl-functies rechtstreeks aanroept, het loopt via dezelfde libcurl. Wat verholpen moet worden, is het libbrotli-pakket op de server; tot de gepatchte versie er is, kun je het automatische uitpakken van externe WordPress-verzoeken uitzetten met de instelling uit 5️⃣. Volgens de curl-documentatie pakt code die curl-functies rechtstreeks aanroept zonder [CURLOPT_ENCODING] in te stellen gecomprimeerde antwoorden niet automatisch uit. Code die ze rechtstreeks aanroept en de waarde op een lege string zet, valt buiten de hook [http_api_curl], dus controleer de verzoeken van die plugin apart.

In de records van CVE-2026-111497 bij NVD en cve.org (CNA Google) staan de plek van het lek (c/dec/decode.c), de getroffen versies en het zwakheidstype. De release notes van google/brotli v1.2.1, v1.1.1 en v1.0.10 vermelden de fix. Details om de aanval na te bootsen staan niet in dit artikel.

ℹ️ Affiliatemelding
De content van deze site bevat affiliatelinks. Koopt een bezoeker via een van deze links een product of dienst, dan ontvangt deze site een commissie van de verkoper. Het bedrag dat de koper betaalt (bij acties gaat het omlaag ↓) wordt daardoor niet hoger. De vermelde prijzen, kortingen en voorraad gelden op het moment van schrijven en kunnen afwijken; controleer ze daarom vóór je aankoop bij de verkoper. Producten worden gekozen en beoordeeld volgens onze eigen criteria, en commissies hebben geen invloed op de volgorde of de inhoud van de beoordelingen.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Laat zien dat je geen machine bent: 4   +   3   =