Dev.to Security 🔐 Cybersecurity 👁 0 📖 11 min read

Votre version de Node.js est-elle vulnérable à la faille RCE Brotli ? Vérifiez en 2 minutes

Votre version de Node.js est-elle vulnérable à la faille RCE Brotli ? Vérifiez en 2 minutes Exécutez cette commande tout de suite. Si votre version est antérieure au seuil minimal indiqué dans le tableau ci-dessous, vo

Votre version de Node.js est-elle vulnérable à la faille RCE Brotli ? Vérifiez en 2 minutes

Votre version de Node.js est-elle vulnérable à la faille RCE Brotli ? Vérifiez en 2 minutes

Exécutez cette commande tout de suite. Si votre version est antérieure au seuil minimal indiqué dans le tableau ci-dessous, votre installation est vulnérable à la RCE Brotli de Node.js (CVE-2026-111497) — et des attaquants l'exploitent déjà activement.

Essayez Apidog dès aujourd'hui

node -v
Branche Vulnérable Corrigée à partir de Dernière version (5 nov. 2026)
26.x Inférieure à 26.12.1 26.12.1 26.13.0
24.x Inférieure à 24.22.1 24.22.1 24.22.2
22.x Inférieure à 22.23.4 22.23.4 22.23.4
25.x, 20.x et antérieures En fin de vie (EOL) : non corrigée et non évaluée Aucun correctif disponible Migrer vers la 24 ou la 26

Pour une seconde vérification, interrogez directement le binaire :

node -p "require('node:zlib').constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"

Le correctif a introduit cette constante. Nous avons testé cette commande sur neuf builds macOS officiels couvrant les trois branches prises en charge : chaque version corrigée a renvoyé -17, tandis que chaque version antérieure a renvoyé undefined. Fiez-vous en priorité à node -v, car une distribution Linux ayant rétroporté le correctif pourrait ne pas exposer cette constante.

Ne vous fiez pas à process.versions.brotli. Cette commande a renvoyé 1.2.0 aussi bien sur la 24.21.0 que sur la 24.22.1, et 1.1.0 sur la 22.23.3 comme sur la 22.23.4. Node.js a intégré le correctif par cherry-pick sans incrémenter le numéro de version affiché : ce champ ne permet donc pas de savoir si votre environnement est sécurisé.

En résumé

Question Réponse
De quoi s'agit-il ? Écriture hors limites (out-of-bounds write) dans le décodeur Brotli intégré à Node.js, également baptisée Node2Shell ou HTTP2Shell
Impact Plantage (crash), fuite de mémoire ou exécution de code à distance (RCE)
Sévérité HIGH (ÉLEVÉE) selon Node.js ; 9.8 CRITICAL (CRITIQUE, CVSS 3.1) selon le NVD
Exploitation active ? Oui. Le catalogue KEV de la CISA l'a répertoriée le 27 octobre 2026
Authentification requise ? Non, d'après le vecteur du NVD et l'analyse d'Akamai
Qui est exposé ? Toute application décodant des flux Brotli non maîtrisés : corps de requêtes dans Express 5, réponses fetch(), appels directs à node:zlib
Solution Mettre à niveau le runtime, reconstruire les images de conteneur, redémarrer les processus
Contournement ? Le bulletin de sécurité n'en mentionne aucun. Les mesures d'atténuation temporaires ci-dessous réduisent l'exposition sans tout couvrir

Timeline of CVE-2026-111497: Node.js fixes on October 21, CVE published October 22, exploit traffic reported October 26, CISA KEV listing October 27, KEV due date November 10, next Node.js security release November 11

ELLIO a signalé du trafic d'exploitation sur ses sondes dès le 26 octobre, soit cinq jours après la publication du correctif. La charge utile interceptée ciblait Node.js 24.22.0 sur architecture x86-64. Si l'étape finale de ce payload a échoué lors des tests d'ELLIO, l'équipe a confirmé avoir réussi à exécuter du code sur des builds 24.22.0 standards. La CISA a accordé aux agences fédérales américaines jusqu'au 10 novembre pour intervenir et indique que l'utilisation par des ransomwares est « Inconnue ». Selon la télémétrie d'Akamai, 61 % des réseaux utilisaient encore des versions vulnérables au 26 octobre.

Comprendre Node2Shell : fonctionnement de la faille Brotli

Node2Shell est une vulnérabilité d'écriture hors limites située dans le décodeur Brotli intégré au runtime Node.js. Un flux compressé malformé pousse le décodeur à écrire au-delà d'un tampon interne de huit octets, corrompant la mémoire du processus. Il peut en résulter un plantage, une fuite de mémoire ou l'exécution de code arbitraire sous le contrôle d'un attaquant sur votre serveur.

La cause fondamentale est une mauvaise classification d'erreur : une commutation de bloc (block switch) invalide a été interprétée comme « données supplémentaires requises » au lieu de « données corrompues », ce qui incitait le décodeur en flux continu à continuer d'ajouter des octets dans ce petit tampon.

La faille provient de la bibliothèque Brotli de Google (versions 1.0.3 à 1.2.0) et ne se limite donc pas à Node.js. Node.js a corrigé sa propre copie en intégrant par cherry-pick le commit amont 0ed4268a dans la version 24.22.1 et les versions associées. Les chercheurs Khai Tran et Sylvie Mayer d'OpenAI Codex Security en sont à l'origine du signalement.

Vos scanners de dépendances ne détecteront pas cette vulnérabilité : le décodeur est intégré directement au runtime et ne provient pas d'un paquet tiers. La commande npm install n'a signalé aucune vulnérabilité (0 vulnerability) sur notre projet de test Express 5 exécuté sur une version non corrigée de Node.js (24.15.0).

Qui est exposé ?

Un runtime vulnérable ne suffit pas à lui seul : encore faut-il qu'un chemin transmette des données Brotli non fiables au décodeur. Nous avons testé chaque vecteur sous Node.js 24.22.1 en envoyant un corps de requête invalide mais inoffensif (le texte not-valid-brotli) avec l'en-tête Content-Encoding: br, ainsi qu'en fournissant du contenu Brotli valide à chaque client.

Vecteur / Chemin Version testée Décodeur exécuté ? Résultat observé
Express 5 express.json() 5.3.0 (body-parser 2.4.0) Oui, par défaut 400, « Decompression failed »
Express 4 express.json() 4.22.3 (body-parser 1.20.9) Non 415, encodage non supporté
Koa @koa/bodyparser 6.1.0 Oui, par défaut 500, erreur BrotliDecoder dans les logs
Fastify avec @fastify/compress 9.3.0 Oui, une fois enregistré 400, FST_CP_ERR_INVALID_CONTENT
Fastify standard 5.12.8 Non 400, JSON invalide
Serveur node:http brut ou http.get 24.22.1 Non Les octets bruts sont transmis tels quels
fetch() natif 24.22.1 Oui, toujours Décodage de la réponse
axios, got, node-fetch 1.21.0, 16.2.0, 3.3.2 Oui, par défaut Décodage de la réponse
zlib.brotliDecompress*, createBrotliDecompress Toutes Oui Il s'agit de l'API du décodeur

Diagram of paths into the Brotli decoder in node:zlib: Express 5 parsers, Koa body parsers and Fastify with @fastify/compress on the inbound side, fetch, axios and got on the outbound side, while Express 4, plain Fastify and bare node:http do not reach it

Deux résultats méritent une attention particulière. fetch() a décodé le flux Brotli même lorsque la requête spécifiait Accept-Encoding: identity, car il se conforme à l'en-tête de la réponse et non à ce qui a été demandé. N'importe quel serveur contacté par votre application peut donc solliciter le décodeur : les outils de test de webhooks, les générateurs d'aperçu de liens ou les importateurs d'URL sont particulièrement exposés. Par ailleurs, un code 400 à lui seul ne prouve rien : Express 5 et Fastify standard renvoient tous deux une erreur 400, mais seul Express 5 a réellement exécuté le décodeur. Examinez attentivement le message d'erreur.

Identifiez vos surfaces d'exposition à l'aide de ces trois commandes :

# Direct decoder use
grep -rnE "brotliDecompress|createBrotliDecompress" src/

# Parsers that decode request bodies
npm ls express body-parser @koa/bodyparser @fastify/compress

# Base images and pinned versions
grep -rnE "^FROM .*node" --include='Dockerfile*' .

Un seul nouvel appel à fetch() suffit à changer la donne : même si vous vous pensez « non exposé », la mise à jour reste indispensable.

Comment corriger la CVE-2026-111497

Passez directement à la version la plus récente de votre branche, et pas seulement à la version minimale requise. Au 5 novembre, toutes ces sources proposaient des builds corrigés :

Méthode d'installation Action à mener
nvm nvm install 24 && nvm alias default 24
Homebrew brew upgrade node (ou node@24, node@22)
Docker FROM node:24.22.2-slim, puis docker build --pull
Paquets de distribution Linux Consultez les avis de sécurité de votre distribution, car le correctif peut avoir été rétroporté sous un numéro de version antérieur
CI Mettez à jour .nvmrc, engines et node-version, puis relancez le build
Serverless Affichez process.version dans les logs d'une fonction déployée ; ne supposez pas que la plateforme l'a mise à jour automatiquement

Veillez ensuite à combler les deux angles morts qui piègent le plus souvent les équipes :

  • Redémarrez tous les processus. Un processus en cours d'exécution conserve l'ancien binaire en mémoire : la mise à niveau sur le disque ne sert à rien tant que pm2, systemd ou votre orchestrateur ne l'a pas redémarré.
  • Reconstruisez tout ce que vous avez déployé. Les anciennes images conservent l'ancien runtime, et les images épinglées par digest (sha256) doivent faire l'objet d'un scan d'image car le tag ne fournit aucune indication.

Terminez en exécutant les vérifications du début de cet article directement dans le conteneur déployé, puis sur les exécuteurs CI et les postes de développement. Pour afficher la build de sécurité la plus récente de chaque branche :

curl -s https://nodejs.org/dist/index.json | jq -r '[.[] | select(.security == true and (.version | test("^v(22|24|26)\\.")))] | group_by(.version | split(".")[0]) | .[] | max_by(.date) | "\(.version)  \(.date)"'

Vous utilisez encore la version 20 ou 25 ? Aucun build n'existe pour vous. Consultez le calendrier de fin de vie de Node.js 20 et migrez sans attendre.

Mesures d'atténuation si vous ne pouvez pas appliquer le correctif aujourd'hui

Ces solutions permettent de gagner du temps, mais aucune ne remplace une véritable mise à niveau.

  1. Rejetez br à la périphérie (edge). Bloquez Content-Encoding: br au niveau de votre proxy inverse ou de votre répartiteur de charge (load balancer), avec une correspondance insensible à la casse et capable de traiter des listes comme gzip, br.
  2. Rejetez-le au niveau de l'application. Placez ce middleware en amont de vos analyseurs de corps de requête (body parsers). Il a renvoyé un code 415 lors de notre test avec Express 5 :
   app.use((req, res, next) => {
     const encoding = req.headers['content-encoding'] || '';
     if (/\bbr\b/i.test(encoding)) return res.status(415).end();
     next();
   });
  1. Désactivez la décompression automatique. L'option express.json({ inflate: false }) a renvoyé une erreur 415 pour la même requête. Attention : elle rejette aussi les corps compressés en gzip, vérifiez donc au préalable la compatibilité avec vos clients.
  2. Contrôlez les réponses sortantes. axios accepte le paramètre decompress: false, ce qui a permis de conserver les octets non décodés lors de notre test. fetch() n'offre aucun mécanisme standard de désactivation : limitez donc les hôtes qu'il peut contacter à l'aide d'une liste blanche et de règles de filtrage en sortie (egress).
  3. Limitez le rayon d'impact. Segmentez vos services Node.js et restreignez l'accès en lecture aux fichiers d'image mémoire (core dumps), car ELLIO souligne que les plantages peuvent y divulguer des données résidant en mémoire.

Surveillez les signes précurseurs détectés par ELLIO : des vagues de requêtes encodées en Brotli visant à identifier quels serveurs les décompressent. L'apparition inhabituelle de trafic avec Content-Encoding: br sur une API JSON ou une hausse anormale des plantages de workers justifie une enquête immédiate.

Vérifiez que votre API fonctionne toujours après la mise à niveau : confiez les tests à votre agent

Le passage à une nouvelle version majeure du runtime peut modifier le comportement de TLS, du DNS et de HTTP — et la mise à jour d'octobre a justement touché à ces trois aspects. Ne vérifiez pas ces écarts manuellement : laissez votre agent de développement exécuter Apidog CLI avant et après la mise à niveau, puis vous signaler tout changement de comportement.

npm install -g apidog-cli@latest
apidog login --with-token <YOUR_TOKEN>
npx -y skills add https://apidog.com   # pick your agent when prompted

Transmettez ce prompt à votre agent :

Run Apidog test suite <id> in project <id> against staging and save the
results to reports/before. After I upgrade Node.js, add a test case for
POST /orders that sends the plain text "not-valid-brotli" with
Content-Encoding: br, asserts a 4xx status, then checks GET /health
returns 200. Rerun the suite to reports/after and list every request
whose result changed.

L'agent exécute ensuite les commandes suivantes :

apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/before
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case.json
apidog test-case create --project <id> --file case.json
apidog run --test-case <caseId> --project <id> -e <envId> -r cli,json
apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/after

Ce cas de test supplémentaire sert de test de santé (health check) et non d'exploit : le corps envoyé est du texte brut, et il a échoué avec la même erreur de padding sur les versions vulnérables et corrigées lors de nos essais. Il révèle cependant une véritable lacune opérationnelle : notre test Koa a renvoyé un code 500 car l'erreur de décodage n'était pas interceptée, alors qu'une API publique devrait renvoyer une erreur 4xx. N'exécutez ce test que sur un environnement de préproduction (staging).

La documentation de référence de la commande run détaille l'ensemble des options disponibles, et le guide CI/CD vous montre comment intégrer cette même exécution JUnit dans votre pipeline. Le forfait gratuit (Free) d'Apidog accueille jusqu'à 4 utilisateurs.

Pourquoi l'échéance du 11 novembre est cruciale

Le projet Node.js a annoncé une nouvelle série de correctifs pour les branches 26.x, 24.x et 22.x, prévue le 11 novembre 2026 ou peu après, avec une sévérité maximale à nouveau classée HIGH. Aucun identifiant CVE n'est encore public. Notre guide sur les versions de novembre explique comment vous y préparer.

Corrigez la vulnérabilité Brotli dès aujourd'hui plutôt que d'attendre cette prochaine fenêtre : les détails techniques de la faille sont publics et des attaques réelles ont lieu en ce moment même. La mise à niveau menée cette semaine servira en outre de répétition générale pour la suivante — même inventaire, même reconstruction d'images, même suite de tests. Les affaires PHP2Shell et React2Shell ont suivi la même trajectoire.

FAQ

La faille CVE-2026-111497 fait-elle l'objet d'exploitations actives ? Oui. La CISA l'a inscrite à son catalogue KEV (Known Exploited Vulnerabilities) le 27 octobre 2026 sous le libellé Google Brotli, et ELLIO a observé du trafic d'exploitation dès le 26 octobre.

Sa sévérité est-elle Élevée (HIGH) ou Critique (CRITICAL) ? Les deux qualifications sont légitimes. Node.js la classe HIGH. Le NVD lui attribue un score CVSS 3.1 de 9.8 CRITICAL, et le score CVSS 4.0 publié par Google atteint 9.2. Organisez-vous en partant du principe qu'elle est activement exploitée.

J'utilise Express 4. Suis-je à l'abri ? Vos corps de requête n'atteignent pas le décodeur, mais les appels à fetch(), axios et node:zlib restent vulnérables. Par ailleurs, cette même version corrige neuf autres CVE : mettez donc à niveau sans hésiter.

Node.js 20 est-il concerné ? L'équipe du projet n'évalue pas les branches en fin de vie (EOL) et ne publie aucun correctif pour celles-ci. Considérez les versions 20.x et 25.x comme non corrigées et non évaluées, et planifiez votre migration.

D'autres technologies que Node.js sont-elles touchées ? Oui. Le bulletin de sécurité GitHub mentionne les paquets PyPI brotli et brotlicffi, et des correctifs ont été signalés pour Bun 1.4.4 ainsi que pour .NET. Mettez à jour chaque décodeur séparément, car la mise à niveau de Node.js ne protège que sa propre bibliothèque intégrée.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.