Node2Shell : RCE Brotli dans Node.js, Bun et Python (CVE-2026-111497)
Dépassement de tampon du décodeur noté CVSS v4.0 9,2, CVE-2026-111497 touche Node.js, Bun, .NET, les paquets Brotli de Python, Envoy et Istio ; les correctifs ont été publiés du 21 au 25 octobre 2026.
En bref
- CVE-2026-111497 est une écriture hors limites dans le décodeur Brotli en C, le code qui décompresse les données Brotli (
Content-Encoding: br) sur le Web. Un flux spécialement conçu corrompt la mémoire du processus et provoque un plantage, une divulgation de mémoire ou une exécution de code. La fiche CVE lui attribue un score CVSS v4.0 de 9,2 (CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N) ; Node.js classe sa sévérité comme élevée et Red Hat lui attribue 8,1. - Le défaut se trouve dans Google Brotli 1.0.3 à 1.2.0 et se propage à tout ce qui embarque ce code : Node.js 22.x, 24.x et 26.x, Bun 1.4.3 et antérieures, les paquets PyPI Brotli et brotlicffi, Envoy et Istio lorsque la décompression Brotli est activée, les builds autonomes de cdxgen et le runtime .NET, corrigé le 25 octobre de .NET 8 jusqu'aux versions candidates de .NET 11.
- L'exposition nécessite de décoder des données Brotli contrôlées par un tiers : une réponse
fetch(), un corps de requête Express 5 ou body-parser 2, un filtre de décompression de proxy ou des clients HTTP Python, qui décodent automatiquement Brotli dès que le paquet est installé. - Aucune exploitation réelle n'est connue : l'évaluation de CISA du 23 octobre indique une exploitation « none ». La red team d'Imperva a démontré l'exécution de code sur un build ARM64 non modifié de Node.js 24.22.0 et n'a pas publié l'exploit ; la preuve de concept publique apparue le 22 octobre n'atteint l'exécution de code que sur un build volontairement affaibli, et produit un plantage et une lecture limitée de mémoire sur les builds standards. Red Hat indique qu'il n'existe aucune preuve de concept publique fiable permettant d'exécuter du code.
- Mettez à jour toutes les copies du décodeur dès maintenant, puis redémarrez les services et reconstruisez les images de conteneurs : un processus en cours conserve l'ancien décodeur jusqu'à son redémarrage.
Suis-je concerné ?
Vous êtes concerné si ces deux conditions sont réunies :
- Un logiciel que vous exécutez embarque le décodeur Brotli ou y est lié dans une version affectée et décode des données Brotli de parties que vous ne contrôlez pas entièrement. Un simple serveur HTTP Node.js ne décode pas lui-même les corps de requêtes ; l'exposition passe donc par les chemins détaillés ci-dessous.
- Pour Python, le risque vient de la simple présence du paquet Brotli ou brotlicffi. Dès que l'un est installé, les clients HTTP comme requests, urllib3, httpx et aiohttp décodent eux-mêmes les réponses Brotli ; une application peut donc être exposée sans jamais importer Brotli dans son propre code.
| Logiciel | Versions affectées | Version corrigée |
|---|---|---|
| Google Brotli (bibliothèque C) | 1.0.3 à 1.2.0 | 1.0.10, 1.1.1 ou 1.2.1, selon la branche (21 octobre 2026) |
| Node.js 26.x | Avant 26.12.1 | 26.12.1 (21 octobre 2026) |
| Node.js 24.x | Avant 24.22.1 | 24.22.1 (21 octobre 2026) |
| Node.js 22.x | Avant 22.23.4 | 22.23.4 (21 octobre 2026) |
| Node.js 20.x et antérieures | Toutes (fin de vie) | Aucune : passez à une branche prise en charge |
| Bun | 1.4.3 et antérieures | 1.4.4 (22 octobre 2026) |
| .NET 8 | 8.0.0 à 8.0.32 | 8.0.33 (25 octobre 2026) |
| .NET 9 | 9.0.0 à 9.0.21 | 9.0.22 (25 octobre 2026) |
| .NET 10 | 10.0.0 à 10.0.13 | 10.0.14 (25 octobre 2026) |
| Préversions et RC de .NET 11 | 11.0.0-preview.1 à 11.0.0-rc.3.26522.147 | 11.0.0-rc.3.26522.148 |
| PyPI Brotli | Avant 1.2.1 | 1.2.1 |
| PyPI brotlicffi | Avant 1.2.1.0 | 1.2.1.0 |
| Go, andybalholm/brotli | Avant 1.2.7 | 1.2.7 (23 octobre 2026) |
| Envoy | 1.36.11, 1.37.7, 1.38.5, 1.39.2 | 1.36.12, 1.37.8, 1.38.6, 1.39.3, 1.40.0 |
| Istio | 1.29.0 à 1.29.8, 1.30.0 à 1.30.5, 1.31.0 à 1.31.1 | 1.29.9, 1.30.6, 1.31.2 |
| Binaires et images autonomes de cdxgen | 13.4.0 et antérieures, 12.8.8 et antérieures | 13.5.0, 12.8.9 |
| Builds officiels PHP pour Windows | 8.5.12, 8.4.27, 8.3.36 et 8.2.35 du 21 octobre 2026 (Brotli 1.2.0 embarqué, selon leurs SBOM) | 8.5.12-1, 8.4.27-1, 8.3.36-1 et 8.2.35-1, les reconstructions du 26 octobre embarquant Brotli 1.2.1 |
L'avis .NET, GHSA-p3jp-9v83-76w9 (sévérité élevée, CVSS v3.1 8,1), couvre 225 paquets NuGet sur les quatre branches et impose la même condition préalable que les proxies : ASP.NET Core et HttpClient ne décompressent pas automatiquement les données Brotli dans leur configuration par défaut. Une application .NET n'est donc exposée que si elle active la décompression Brotli ou utilise explicitement BrotliStream, BrotliDecoder ou les options de décompression automatique sur des données contrôlées par un attaquant. .NET Framework n'est pas affecté.
Le portage Go du décodeur, andybalholm/brotli, contenait le même retour ambigu dans decodeBlockTypeAndLength. Andy Balholm l'a corrigé le 23 octobre 2026 avec le commit 33c2a988, un portage direct du correctif Google 0ed4268, publié en v1.2.7 sans avis ni CVE. La portée est plus restreinte que celle du décodeur C : les accès aux slices de Go vérifient les limites et transforment l'indice de type de bloc hors plage en panic plutôt qu'en écriture silencieuse hors limites. Le mode de défaillance en Go est donc un plantage sur une entrée fournie par l'attaquant, et non la corruption mémoire permise par la bibliothèque C. Les services Go qui décompressent du Brotli fourni par des attaquants doivent tout de même passer à 1.2.7 ou ultérieure.
Au-delà du tableau, les projets qui compilent leur propre copie du décodeur héritent du défaut jusqu'à sa mise à jour ; un suivi communautaire les recense. Corrigés au 24 octobre : la gem Ruby brotli 0.9.1, l'extension PHP brotli 0.21.1 et UEFITool A76, tous embarquant Brotli 1.2.1, ainsi que MuPDF 1.28.x, dont le fork de Brotli avait intégré le correctif en avril. Toujours sans version corrigée au 27 octobre : ClickHouse, NanaZip, GraalJS (graal-nodejs), YDB et libjxl, qui ont fusionné le correctif dans leurs branches principales mais dont les dernières versions embarquent encore un décodeur affecté, et Apache Arrow, dont le changement C++ imposant des versions plus récentes de Brotli, la pull request #55167, n'était toujours pas fusionné.
Une copie embarquée est arrivée tard et mérite d'être identifiée précisément, car une vérification de version ne la détecte pas. Les builds officiels PHP pour Windows des versions de sécurité du 21 octobre, 8.5.12, 8.4.27, 8.3.36 et 8.2.35, indiquaient Brotli 1.2.0 dans leur nomenclature logicielle. L'extension cURL peut l'atteindre lorsqu'une application active la décompression automatique des réponses HTTP, que cURL laisse désactivée par défaut selon la PHP Foundation, mais que les applications et bibliothèques clientes HTTP peuvent activer. Le 26 octobre, l'équipe PHP a reconstruit les quatre versions sous les noms 8.5.12-1, 8.4.27-1, 8.3.36-1 et 8.2.35-1 avec Brotli 1.2.1 ; le code source PHP reste inchangé, donc php -v affiche la même version avant et après. Seuls le suffixe -1 du nom de paquet et le SHA-256 de la page de téléchargement identifient la reconstruction. Guzzle est la bibliothèque cliente qui remplit par défaut la condition d'exposition : son gestionnaire cURL définit CURLOPT_ENCODING à une valeur vide dès que l'option decode_content n'est pas false, selon son code en 7.16.1 et 8.3.1. Une valeur vide indique à cURL d'accepter et de décompresser tous les encodages qu'il prend en charge.
Envoy et Istio sont affectés lorsque la décompression Brotli est explicitement activée, par exemple via un filtre de décompression Envoy. Lorsqu'elle est désactivée, la faille n'est pas accessible.
Vérifiez ce que vous exécutez sur les hôtes, dans les conteneurs et dans les images CI :
node --version && node -p "process.versions.brotli" # Node.js: runtime and bundled decoder
bun --version # Bun 1.4.4+ is fixed
python -m pip show Brotli brotlicffi 2>/dev/null | grep -E '^(Name|Version)'
envoy --version # only meaningful with decompression enabled
istioctl version
curl -V | grep -o 'brotli/[0-9.]*' # brotli library linked into curl, e.g. brotli/1.1.0
go list -m all | grep brotli # Go: andybalholm/brotli 1.2.7+ is fixed
Pour Node.js, le fichier de verrouillage ne répond pas à la question : les applications décodent Brotli via le module intégré node:zlib, qui utilise le décodeur embarqué dans le runtime. C'est donc la version Node.js ci-dessus qu'il faut vérifier. Le paquet npm brotli est un portage JavaScript distinct utilisé pour les polices WOFF2, pas le décodeur C, et sa présence ou son absence dans package-lock.json n'indique rien sur l'exposition. Pour Python, les dépendances épinglées comptent :
grep -iE '^(brotli|brotlicffi)' requirements.txt
Le paquet PyPI Brotli enregistrait environ 82,8 millions de téléchargements par mois ; cette dépendance est donc très répandue dans les piles applicatives et CI.
Comment corriger le problème ?
Mettez le décodeur à jour partout où il se trouve, puis redémarrez le processus et reconstruisez les images de conteneurs : le processus en cours conserve l'ancien décodeur en mémoire jusqu'à son redémarrage.
- Node.js : passez à 26.12.1, 24.22.1 ou 22.23.4, issues des versions de sécurité du 21 octobre 2026. Node.js 20.x est en fin de vie et ne recevra pas le correctif ; migrez ces déploiements vers une branche prise en charge.
- Bun : passez à 1.4.4, publiée le 22 octobre 2026.
- Python : exécutez
pip install --upgrade Brotli brotlicffipour atteindre 1.2.1 et 1.2.1.0, puis reconstruisez les images qui épinglent l'un de ces paquets. - Go : mettez andybalholm/brotli à jour vers 1.2.7 ou ultérieure dans tout service décompressant du Brotli fourni par des attaquants.
- .NET : passez à 8.0.33, 9.0.22, 10.0.14 ou 11.0.0-rc.3.26522.148. L'exposition exige que la décompression Brotli soit explicitement activée ou que les API Brotli traitent des données contrôlées par l'attaquant ; .NET Framework n'est pas affecté. Les déploiements autonomes et NativeAOT embarquent leur propre runtime : mettre à jour celui partagé par la machine ne les corrige pas. Reconstruisez et redéployez les applications autonomes avec le runtime mis à jour, et republiez les applications NativeAOT avec le SDK corrigé. Selon le suivi communautaire, les branches publiques GitHub n'avaient pas encore rattrapé le correctif interne ; les builds issus du code source GitHub restaient donc affectés.
- Envoy et Istio : passez aux versions corrigées du tableau si votre configuration active la décompression Brotli.
- Google Brotli, si vous compilez directement contre cette bibliothèque : 1.0.10, 1.1.1 ou 1.2.1 selon votre branche.
- PHP sous Windows : installez les reconstructions -1, 8.5.12-1, 8.4.27-1, 8.3.36-1 ou 8.2.35-1, depuis la page de téléchargement PHP et vérifiez le SHA-256, car
php -vne peut pas les distinguer des builds du 21 octobre. En attendant la reconstruction, la solution de contournement côté PHP consiste à arrêter la décompression automatique : ne définissez pasCURLOPT_ENCODINGet, dans Guzzle, définissez l'option de requêtedecode_contentà false. Cela arrête tout décodage automatique, donc les réponses gzip arrivent également compressées. - curl et les autres outils liés à la bibliothèque système : mettez à jour le paquet du système d'exploitation. Debian a corrigé brotli 1.1.0 pour Debian 13 (trixie) le 23 octobre 2026 sous la version 1.1.0-2+deb13u1 ; Amazon Linux 2023 indiquait encore ses paquets brotli et Node.js 24 comme en attente d'un correctif au 22 octobre 2026. Vérifiez donc l'état de votre distribution.
Si vous ne pouvez pas encore mettre à jour, cessez de décoder du Brotli non fiable. Voici les recommandations de la page de divulgation d'OpenAI et d'Aikido :
- Rejetez les requêtes entrantes portant
Content-Encoding: bravant qu'un proxy ou un analyseur ne décode le corps. - Désactivez le décodage automatique Brotli dans les clients HTTP et rejetez les réponses Brotli avant leur décodage.
- Dans Python, désinstallez les paquets Brotli et brotlicffi afin que les clients se replient sur gzip et deflate.
Les limites doivent être claires. Retirer br de l'en-tête Accept-Encoding ne suffit pas, car un serveur peut envoyer du Brotli quelle que soit la demande du client. Pour Node.js lui-même, aucune solution de contournement générale n'a été publiée ; la mise à jour du runtime est donc le seul correctif. Un chemin entrant peut toutefois être fermé en attendant : les analyseurs Express 5 et body-parser 2 configurés avec inflate: false rejettent tout corps de requête compressé avec une erreur 415 avant décompression, mais cela ne protège ni les réponses fetch() ni les autres codes décodant Brotli. Un pare-feu applicatif Web n'aide que partiellement : Vercel, qui a publié des règles le jour de la divulgation, précise qu'elles ne couvrent pas « les réponses que vos fonctions récupèrent sur d'autres serveurs », un chemin que seule la mise à jour du runtime ferme.
Quelle est la cause racine ?
Le décodeur signalait une erreur de format permanente comme une condition récupérable de « besoin de données supplémentaires », et le chemin de décodage rapide ignorait même ce signal. Le décodage continuait donc au-delà du point où il aurait dû s'arrêter et écrivait hors d'un tampon interne. La faille se trouve dans DecodeBlockTypeAndLength, dans c/dec/decode.c, et le correctif, commit 0ed4268 d'Evgenii Kliuchnikov du 27 février 2026, en montre le mécanisme.
Avant le correctif, la fonction renvoyait BROTLI_BOOL, le booléen de la bibliothèque. BROTLI_FALSE signifiait deux choses très différentes : un flux mal formé et une lecture incomplète que davantage de données pouvait résoudre :
static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
int safe, BrotliDecoderState* s, int tree_type) {
...
if (max_block_type <= 1) {
- return BROTLI_FALSE;
max_block_type <= 1 signifie que le flux déclare un seul type de bloc ; une commande de changement de bloc à cet endroit constitue donc une entrée invalide, pas une lecture en pause. L'appelant ne pouvait pas distinguer les deux cas. Pour le chemin en streaming, Node.js décrit la conséquence : « un changement de bloc invalide était signalé comme un besoin temporaire de données supplémentaires plutôt que comme une erreur de format permanente ; le décodeur en streaming continuait donc à ajouter des octets d'entrée à un tampon interne de huit octets ».
Dans le chemin rapide, le résultat était entièrement ignoré. La variante non sûre du changement de bloc littéral était déclarée void, donc l'échec ne remontait jamais à l'appelant :
-static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s) {
- DecodeLiteralBlockSwitchInternal(0, s);
La macro BROTLI_SAFE, utilisée aux trois points d'appel du changement de bloc, vérifie le résultat en mode sûr spéculatif et l'ignore en mode non sûr. Le correctif ajoute un commentaire explicite : « en cas d'exécution 'non sûre', lorsque l'entrée est garantie suffisante, le résultat est ignoré ». Cette garantie valait pour les flux bien formés, pas pour ceux contenant un changement de bloc invalide. Le chemin rapide continuait donc à décoder avec un état périmé du tampon circulaire des types de blocs et de l'arbre Huffman, et les écritures suivantes dépassaient la fin de leur tampon. L'avis GitHub associe la faille à CWE-252, valeur de retour non vérifiée ; le dépassement lui-même est une CWE-787, écriture hors limites.
Comment la faille est-elle exploitée ?
L'attaque nécessite un chemin de livraison où la cible décompresse du Brotli contrôlé par l'attaquant, puis un flux spécialement conçu. Étape par étape :
- L'attaquant construit un flux Brotli qui atteint
DecodeBlockTypeAndLengthavec une commande de changement de bloc alors que le flux ne déclare qu'un type de bloc pour cet arbre. - Le flux est livré comme réponse
Content-Encoding: brà un appelfetch(), comme corps de requête compressé en Brotli analysé par Express 5 ou body-parser 2, via un filtre de décompression Envoy ou Istio, ou comme réponse automatiquement décodée par un client HTTP Python avec Brotli installé. - Le changement de bloc invalide renvoie
BROTLI_FALSE. Le chemin en streaming l'interprète comme « fournissez-moi davantage d'octets » ; le chemin rapide l'ignore. Dans les deux cas, le décodage continue au lieu de rejeter le flux. - Le décodage avec un état périmé de type de bloc écrit des données influencées par l'attaquant au-delà d'un tampon interne du décodeur et corrompt la mémoire adjacente du processus.
- La corruption fait planter le processus, divulgue de la mémoire ou redirige l'exécution. La red team d'Imperva, qui a nommé son travail Node2Shell, a exécuté du code fourni par l'attaquant sur un build non modifié de Node.js 24.22.0 pour Linux ARM64, en livrant le payload à la fois comme réponse récupérée et comme corps de requête Express. L'exploit a nécessité plusieurs essais, n'a pas été publié et n'a pas été testé sur d'autres builds.
L'équipe Codex Security d'OpenAI, qui a signalé la faille, décrit une exposition dans les deux sens : « un serveur non corrigé acceptant des entrées compressées pourrait être pris en main par un client malveillant, et un client non corrigé acceptant des entrées compressées (comme 'curl --compressed') pourrait être pris en main par un serveur malveillant ».
Quel est le déroulement de l'attaque ?
Le déroulement est court : livrer un flux spécialement conçu via n'importe quel chemin de décodage Brotli, laisser l'erreur ambiguë maintenir le décodeur actif après un changement de bloc invalide, puis laisser les écritures suivantes tomber hors du tampon.
une commande de changement de bloc invalide"] --> B["Livré par réponse fetch,
corps de requête ou filtre proxy"] B --> C["Le décodeur rencontre le changement invalide :
erreur de format, pas manque de données"] C --> D["Le booléen TRUE ou FALSE confond
les deux : signalement d'erreur défaillant"] D --> E["Le chemin rapide ignore le résultat
et poursuit le décodage"] E --> F["L'état périmé du type de bloc provoque
des écritures au-delà du tampon"] F --> G["Plantage, divulgation de mémoire
ou exécution de code"]
Que peut faire un attaquant ?
- Faire planter le processus de décodage. Le déni de service est l'issue la plus fiable, car une corruption du tas entraîne souvent un plantage avant toute autre conséquence.
- Divulguer la mémoire du processus. L'état adjacent du décodeur et le contenu du tas peuvent fuiter via les résultats de décodage corrompus.
- Exécuter du code. Imperva l'a démontré sur un build Node.js ; la fiabilité dépend de l'organisation du tas du processus. C'est pourquoi la démonstration a nécessité plusieurs tentatives et qu'aucun exploit public fiable n'existe, selon Red Hat.
- Compromettre les clients autant que les serveurs. Un client non corrigé qui décode du Brotli provenant d'un serveur malveillant ou compromis est exposé de la même manière, par un chemin que la plupart des mesures de durcissement serveur ne couvrent pas.
Conditions nécessaires à l'attaquant : un chemin de décodage pour du Brotli qu'il contrôle, comme ceux énumérés ci-dessus, et rien d'autre. Aucune authentification au-delà de celle de l'échange HTTP porteur, ni interaction utilisateur pour le décodage côté serveur.
Pourquoi le correctif fonctionne-t-il ?
Le commit 0ed4268, « Détecter et signaler plus tôt les flux invalides », reconstruit la gestion des erreurs pour que les deux états ne se réduisent plus à un seul booléen :
DecodeBlockTypeAndLengthrenvoie désormaisBrotliDecoderErrorCode, à trois états : succès, erreur définitive ou besoin de données supplémentaires.- Le cas du changement de bloc invalide renvoie une nouvelle erreur permanente,
BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, code -17, auparavant laissé comme « réservé » dans l'en-tête. - Les lectures incomplètes renvoient distinctement
BROTLI_DECODER_NEEDS_MORE_INPUT, afin que la boucle en streaming conserve son comportement légitime de reprise. - Une nouvelle macro
BROTLI_SAFE_WITH_STATUSvérifie l'état dans les chemins sûrs et non sûrs et saute àsaveStateAndReturnen cas d'échec. Le chemin rapide ne peut donc plus ignorer une erreur de changement de bloc :
+#define BROTLI_SAFE_WITH_STATUS(METHOD) \
+ { \
+ BrotliDecoderErrorCode status; \
+ if (safe) { \
+ status = Safe##METHOD; \
+ } else { \
+ status = METHOD; \
+ } \
+ if (status != BROTLI_DECODER_SUCCESS) { \
+ result = status; \
+ goto saveStateAndReturn; \
+ } \
+ }
Les trois points d'appel du changement de bloc utilisent maintenant la macro qui vérifie l'état, et le patch ajoute une assertion de débogage sur l'invariant de longueur du méta-bloc. Le correctif est complet pour cette faille : un changement de bloc invalide est désormais une erreur permanente signalée sur chaque chemin.
La leçon de déploiement compte autant que le code. Le correctif est entré dans le code source de google/brotli le 27 février 2026, et aucune version Brotli ne l'a inclus avant le 21 octobre 2026. Selon OpenAI, la cause racine « avait en réalité été corrigée dans le code source de Brotli en février, mais on ignorait alors qu'elle donnait lieu à une vulnérabilité de sécurité et aucune version plus récente de Brotli n'existait ». Chaque runtime et paquet a ensuite dû distribuer sa propre copie du correctif en octobre, ce qui explique que les versions corrigées ci-dessus s'étalent sur trois jours et huit écosystèmes.
Comment vérifier si j'ai été compromis ?
Aucune exploitation réelle n'a été signalée et aucun indicateur de compromission n'existe pour cette faille. L'évaluation CISA du 23 octobre 2026 indique une exploitation « none » et une automatisation « no ».
En attendant, recherchez globalement des séries de plantages de processus Node.js, Bun, Envoy ou Istio traitant du trafic encodé en Brotli, des anomalies de contenu mémoire dans leurs dumps de plantage et, si une exécution de code a eu lieu sur un hôte, les artefacts habituels au niveau processus : processus enfants inattendus et connexions sortantes. Tout résultat de ce type sur un chemin de décodage Brotli mérite d'être considéré comme lié jusqu'à preuve du contraire. La réponse est celle d'une suspicion d'exécution de code : isoler, prendre un instantané, renouveler les secrets accessibles au processus et reconstruire à partir d'une image saine.
Chronologie
- 2026-02-27 : le commit
0ed4268est intégré à google/brotli avec le correctif ; aucune version ne suit et l'impact de sécurité n'est pas encore reconnu. - 2026-10-21 : Node.js publie 26.12.1, 24.22.1 et 22.23.4, et google/brotli publie 1.0.10, 1.1.1 et 1.2.1.
- 2026-10-22 : publication de CVE-2026-111497 avec un score CVSS v4.0 de 9,2 ; sortie de Bun 1.4.4 ; publication de l'avis GitHub GHSA-9v8h-qqgm-4m35 pour les paquets Python.
- 2026-10-23 : la démonstration Node2Shell d'Imperva est rapportée ; CISA n'enregistre aucune exploitation ; l'avis GitHub est mis à jour pour associer brotli de pip avant 1.2.1 et brotlicffi avant 1.2.1.0 ; Debian corrige le paquet brotli de trixie ; PYSEC-2026-4322 et PYSEC-2026-4323 sont ajoutés ; Andy Balholm porte le correctif dans le décodeur Go sous le commit 33c2a988 et le publie dans andybalholm/brotli v1.2.7.
- 2026-10-24 : publication de matrices des versions affectées dans les différents écosystèmes.
- 2026-10-25 : Microsoft publie l'avis .NET GHSA-p3jp-9v83-76w9, corrigeant 225 paquets NuGet de .NET 8, 9, 10 et des versions candidates de 11 ; le suivi communautaire recense les correctifs du 24 octobre de la gem Ruby brotli, de l'extension PHP brotli et d'UEFITool.
- 2026-10-26 : PHP reconstruit ses paquets officiels Windows sous les noms 8.5.12-1, 8.4.27-1, 8.3.36-1 et 8.2.35-1 avec Brotli 1.2.1, cinq jours après les builds du 21 octobre dont les SBOM indiquaient Brotli 1.2.0.
- 2026-10-25 : cet article, mis à jour le 27 octobre avec les reconstructions PHP pour Windows, la condition d'exposition de Guzzle et l'état d'Apache Arrow.
FAQ
Un simple serveur HTTP Node.js est-il exposé ?
Un simple serveur Node.js ne décode pas lui-même les corps de requêtes et se situe donc hors des chemins démontrés. L'exposition apparaît lorsqu'il analyse des corps Brotli via Express 5 ou body-parser 2, lorsqu'il appelle fetch() et décode une réponse Content-Encoding: br, ou lorsque son code transmet des données non fiables à zlib.brotliDecompress(), zlib.createBrotliDecompress() ou aux autres API Brotli de node:zlib, par exemple dans un gestionnaire WebSocket, un flux RPC ou un pipeline de traitement de fichiers. Si aucun de ces cas ne se présente dans votre code, il reste utile de mettre le runtime à jour selon votre calendrier.
Retirer br d'Accept-Encoding protège-t-il mes clients ?
Non. Un serveur peut envoyer du Brotli quelle que soit la demande du client, et les clients Python décodent automatiquement Brotli dès que le paquet est installé. Désactivez le décodage automatique Brotli dans la configuration du client, rejetez les réponses Brotli avant leur décodage ou désinstallez les paquets Python pour que les clients se replient sur gzip et deflate.
Pourquoi le correctif a-t-il attendu de février à octobre pour atteindre les utilisateurs ?
Le changement est entré dans le code source de google/brotli le 27 février 2026, mais le projet n'a publié aucune version entre cette date et la réponse de sécurité d'octobre, et l'impact de sécurité du changement était alors inconnu. Les runtimes qui embarquent le décodeur, dont Node.js et Bun, ne pouvaient pas intégrer le correctif avant qu'une version soit disponible à embarquer.
Mon scanner de dépendances signalera-t-il les paquets Python ?
L'avis GitHub associe désormais brotli de pip avant 1.2.1 et brotlicffi avant 1.2.1.0, depuis sa mise à jour du 23 octobre 2026, et les entrées PYSEC-2026-4322 et PYSEC-2026-4323 existent. Les outils synchronisant leurs bases peuvent donc les signaler. Les outils anciens ou isolés peuvent prendre du retard ; vérifier manuellement les versions installées, comme ci-dessus, reste le test fiable cette semaine.
Envoy et Istio sont-ils exposés par défaut ?
Non. Tous deux sont affectés lorsque la décompression Brotli est explicitement activée, par exemple via un filtre de décompression Envoy. Si votre configuration ne décompresse jamais Brotli, la faille est inaccessible ; sinon, les versions corrigées du tableau s'appliquent.
Qu'en est-il de curl et des autres outils système ?
curl et de nombreux autres outils sont liés à la bibliothèque Brotli du système d'exploitation plutôt que de l'embarquer. curl -V indique la version liée, par exemple brotli/1.1.0. Mettez à jour via la distribution : Debian a publié le paquet corrigé de trixie le 23 octobre 2026, et les autres distributions suivent leur propre calendrier.
Trouvez l'ancien décodeur avant un attaquant
Scannez vos dépôts, images de conteneurs et services exposés à Internet avec Ostorlab pour repérer tous les déploiements Node.js, Bun et Python qui embarquent encore un décodeur Brotli antérieur aux correctifs du 21 octobre 2026.
Références
- Fiche CVE-2026-111497 avec le vecteur CVSS v4.0 9,2 et la plage affectée de 1.0.3 à 1.2.0 : https://cveawg.mitre.org/api/cve/CVE-2026-111497 (consultée le 25 octobre 2026)
- Versions de sécurité Node.js du 21 octobre 2026, avec descriptions par faille, branches affectées, versions corrigées et crédits (signalement : Khai Tran et Sylvie Mayer d'OpenAI Codex Security ; correctifs : Matteo Collina et Antoine du Hamel) : https://nodejs.org/en/blog/vulnerability/october-2026-security-releases (consultées le 25 octobre 2026)
- Commit correctif 0ed4268, « Détecter et signaler plus tôt les flux invalides », Evgenii Kliuchnikov, 27 février 2026 : https://github.com/google/brotli/commit/0ed4268 (consulté le 25 octobre 2026)
- Versions google/brotli 1.0.10, 1.1.1 et 1.2.1, publiées le 21 octobre 2026 : https://github.com/google/brotli/releases (consultées le 25 octobre 2026)
- GHSA-9v8h-qqgm-4m35, avis révisé associant brotli et brotlicffi de pip, avec CWE-252 : https://github.com/advisories/GHSA-9v8h-qqgm-4m35 (consulté le 25 octobre 2026 ; association PyPI ajoutée par la mise à jour du 23 octobre 2026)
- Version Bun 1.4.4, 22 octobre 2026 : https://github.com/oven-sh/bun/releases/tag/bun-v1.4.4 (consultée le 25 octobre 2026)
- Commit correctif andybalholm/brotli 33c2a988, « Détecter et signaler plus tôt les flux invalides », portage du correctif Google du 23 octobre 2026, publié en v1.2.7 : https://github.com/andybalholm/brotli/commit/33c2a988 et https://github.com/andybalholm/brotli/releases/tag/v1.2.7 (consultés le 26 octobre 2026)
- Avis .NET de Microsoft GHSA-p3jp-9v83-76w9, CVE-2026-111497, 225 paquets NuGet corrigés dans 8.0.33, 9.0.22, 10.0.14 et 11.0.0-rc.3.26522.148, avec la condition préalable de décompression automatique et l'indication que .NET Framework n'est pas affecté : https://github.com/dotnet/runtime/security-advisories/GHSA-p3jp-9v83-76w9 et https://github.com/dotnet/announcements/issues/494 (consultés le 26 octobre 2026)
- Suivi communautaire Broccoli2Shell des copies embarquées, état de la preuve de concept publique du 22 octobre (plantage et lecture limitée de mémoire sur les builds standards, exécution de code uniquement sur un build volontairement affaibli) et état des correctifs par projet : https://broccoli2shell.com/ (consulté le 26 octobre 2026)
- Avis Envoy GHSA-3wvj-j6qm-62mr : https://github.com/envoyproxy/envoy/security/advisories/GHSA-3wvj-j6qm-62mr (consulté le 25 octobre 2026)
- Avis de sécurité Istio 2026-007 : https://istio.io/latest/news/security/istio-security-2026-007/ (consulté le 25 octobre 2026)
- Avis cdxgen GHSA-5266-jm88-3grm : https://github.com/cdxgen/cdxgen/security/advisories/GHSA-5266-jm88-3grm (consulté le 25 octobre 2026)
- The Hacker News, « La faille du décodeur Brotli derrière la RCE Node.js touche aussi Bun, Python et d'autres logiciels très utilisés », 24 octobre 2026, avec la matrice des logiciels affectés, la citation bidirectionnelle d'OpenAI, les évaluations CISA et Red Hat et les solutions de contournement recommandées : https://thehackernews.com/2026/10/brotli-decoder-flaw-behind-nodejs-rce.html (consulté le 25 octobre 2026)
- The Hacker News sur la démonstration Node2Shell d'Imperva, 23 octobre 2026 : https://thehackernews.com/2026/10/researchers-demonstrate-node2shell-rce.html (consulté le 25 octobre 2026)
- Page de divulgation d'OpenAI sur la faille, patchtheplanet.org : https://patchtheplanet.org/brotli (référencée via The Hacker News, 24 octobre 2026 ; la page ne s'affiche pas en texte statique depuis cet environnement)
- Évaluation CVE de Red Hat, score 8,1 et constat d'absence de preuve de concept publique fiable : https://access.redhat.com/security/cve/CVE-2026-111497 (référencée via The Hacker News, 24 octobre 2026)
- Bulletin de sécurité Node.js de Vercel sur les limites de ses règles de pare-feu : https://vercel.com/kb/bulletin/node-js-security-advisory (référencé via The Hacker News, 24 octobre 2026)
- Annonce de sécurité Debian pour brotli 1.1.0-2+deb13u1, 23 octobre 2026 : https://lists.debian.org/debian-security-announce/2026/msg00498.html (référencée via The Hacker News, 24 octobre 2026)
- Statistiques de téléchargements PyPI de Brotli, environ 82,8 millions par mois : https://pypistats.org/packages/brotli (consultées le 25 octobre 2026)
- Analyse d'Aikido sur l'exposition des paquets Python et les solutions de contournement : https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497 (référencée via The Hacker News, 24 octobre 2026)
- PHP Foundation, « Builds PHP Windows mis à jour pour le correctif de sécurité Brotli », 26 octobre 2026 : reconstructions -1 de 8.5.12, 8.4.27, 8.3.36 et 8.2.35 avec Brotli 1.2.1, accessibilité via la décompression automatique cURL et sens du suffixe -1 : https://www.php.net/archive/2026.php#2026-10-26-1 (consulté le 27 octobre 2026)
- The Hacker News, « PHP publie une deuxième mise à jour de sécurité Windows en cinq jours pour corriger une faille d'exécution de code Brotli », 26 octobre 2026, avec les preuves SBOM de Brotli 1.2.0 dans les builds du 21 octobre, le constat de configuration par défaut de Guzzle dans son code 7.16.1 et 8.3.1 et les recommandations de contournement d'OpenAI : https://thehackernews.com/2026/10/php-issues-second-windows-security.html (consulté le 27 octobre 2026)
- Code du gestionnaire cURL de Guzzle, 7.16.1,
src/Handler/CurlFactory.php, définissantCURLOPT_ENCODINGà une valeur vide sauf sidecode_contentvaut false : https://github.com/guzzle/guzzle/blob/7.16.1/src/Handler/CurlFactory.php (consulté le 27 octobre 2026) - Pull request Apache Arrow #55167, « GH-55165 : [C++] Imposer des versions plus récentes de Brotli », toujours ouverte au 27 octobre 2026 : https://github.com/apache/arrow/pull/55167 (consultée le 27 octobre 2026)