
Avis et analyse pour CVE-2026-111497, une écriture hors limites du décodeur Brotli accessible via la décompression HTTP de Node.js, avec cause racine, diff de correctif, règles de détection et mesures d'atténuation.
Date de dernière vérification : 2026-11-04 (KST). Chaque valeur indiquée provient uniquement des sources citées dans les References ci-dessous ; lorsque les valeurs diffèrent entre les sources, toutes sont mentionnées.
c/dec/decode.c) ignore la valeur de retour d'erreur d'un changement de bloc (block switch) invalide, poursuit le décodage dans un état corrompu et effectue ainsi une écriture hors des limites du tampon (Out-of-Bounds Write).Brotli/brotlicffi, Bun, .NET, Envoy, Istio, etc. L'impact nécessite un chemin de décompression (decompress) de données Content-Encoding: br contrôlées par l'attaquant.| Élément | Contenu |
|---|---|
| ID CVE | CVE-2026-111497 (GHSA-9v8h-qqgm-4m35) |
| Alias | Node2Shell (nom donné par Imperva), HTTP2Shell, Broccoli2Shell. Contrairement à ce que suggère le nom, il ne s'agit pas d'un défaut du protocole HTTP/2 |
| Date de publication | 2026-10-21 : version de sécurité de Node.js et version corrigée de Brotli / 2026-10-22 : publication de l'enregistrement CVE |
| Découvreurs | OpenAI Codex Security (Khai Tran, Sylvie Mayer) |
| Produits/versions affectés | Google Brotli (libbrotlidec) 1.0.3 ~ 1.2.0 et produits l'intégrant ou s'y liant (voir tableau ci-dessous) |
| Versions corrigées | Brotli 1.0.10 / 1.1.1 / 1.2.1, Node.js 22.23.4 / 24.22.1 / 26.12.1, Python Brotli 1.2.1, brotlicffi 1.2.1.0, Bun 1.4.4 |
| CVSS v4.0 (CNA : Google) | 9.2 Critical — 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 |
| CVSS v3.1 (NVD) | 9.8 Critical — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CVSS v3.1 (Red Hat / Amazon Linux) | 8.1 — CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H (prise en compte de l'exigence d'attaque AT:P et du durcissement de la plateforme) |
| Niveau attribué par les éditeurs | Node.js : High / Red Hat : Important |
| CWE | CWE-787 Out-of-bounds Write (NVD, Red Hat, Centre canadien de cybersécurité) / CWE-252 Unchecked Return Value (description du CISA KEV, également cité comme cause racine dans certains articles d'analyse) |
| Exploitation réelle | Exploitation confirmée. Inscription au CISA KEV le 2026-10-27, échéance d'action pour les agences fédérales : 2026-11-10. Tentatives d'exploitation observées les 26 et 27 octobre par des opérateurs de honeypots (Previdian, ELLIO) |
| Composant | Versions affectées | Versions corrigées |
|---|---|---|
| Google Brotli (C, libbrotlidec) | 1.0.3 ~ 1.2.0 | 1.0.10, 1.1.1, 1.2.1 |
| Node.js 26.x (Current) | antérieures à 26.12.1 | 26.12.1 |
| Node.js 24.x (LTS) | antérieures à 24.22.1 | 24.22.1 |
| Node.js 22.x (LTS) | antérieures à 22.23.4 | 22.23.4 |
| Node.js 25.x / 23.x / 20.x et antérieurs | toutes les versions (EOL) | aucun correctif → migrer vers 22/24/26 |
| Bun | 1.4.3 et antérieurs | 1.4.4 |
Python Brotli (PyPI) | 1.2.0 et antérieurs | 1.2.1 |
Python brotlicffi | antérieurs à 1.2.1.0 | 1.2.1.0 |
| .NET / PowerShell | voir l'avis de l'éditeur | mise à jour d'urgence .NET de Microsoft (dotnet/announcements#494) |
| Envoy / Istio | voir l'avis de l'éditeur | versions corrigées publiées début octobre (sans mention explicite du défaut) |
| VMware SDDC Manager (VCF / vSphere Foundation) | voir l'avis Broadcom | voir l'avis Broadcom |
Chemins d'exposition indirecte : Python requests, urllib3, aiohttp[speedups], httpx décompressent automatiquement les réponses br si Brotli/brotlicffi est installé. curl est également concerné lorsqu'il utilise l'option de décompression.
| Date | Événement |
|---|---|
| 02-27 | Commit de correction appliqué au dépôt google/brotli (marqué comme problème de sécurité, non publié) |
| Début octobre | Publication des versions corrigées d'Envoy / Istio |
| 10-21 | Publication de sécurité de Node.js (22.23.4 / 24.22.1 / 26.12.1), publication de Google Brotli 1.0.10 / 1.1.1 / 1.2.1 |
| 10-22 | Publication de l'enregistrement CVE, Imperva démontre l'exécution de code sur Node.js 24.22.0 (Linux arm64) |
| 10-23 | Distribution des paquets PyPI corrigés |
| 10-25 | Avis et mises à jour de Microsoft .NET |
| 10-26 | ELLIO signale du trafic d'exploitation |
| 10-27 | Ajout au catalogue CISA KEV (échéance de remédiation 11-10) |
⚠️ Certains articles d'analyse rédigés entre le 24 et le 28 octobre indiquent « aucune attaque réelle confirmée, non inscrit au KEV », mais cela reflète la situation antérieure à l'inscription au KEV et diffère donc de l'état actuel.
BROTLI_FALSELe décodage Brotli est une machine à états. Le flux est constitué de métablocs, et à l'intérieur de chaque métabloc apparaissent des instructions qui commutent le type de bloc (block switch) des littéraux, des commandes d'insertion-copie (insert-and-copy command) et des distances.
DecodeBlockTypeAndLength() interprète les changements de bloc et renvoie un BROTLI_BOOL. Le problème est que BROTLI_FALSE était utilisé avec deux significations totalement différentes.
| Signification | Nature | Traitement correct |
|---|---|---|
| Entrée supplémentaire nécessaire (needs more input) | Récupérable | Attendre l'entrée suivante puis reprendre |
| Le métabloc ne contient qu'un seul type de bloc, rendant le changement lui-même impossible | Erreur de format fatale | Rejeter le flux |
L'appelant ne vérifiait pas cette valeur de retour.
DecodeCommandBlockSwitch) est déclaré static void et ne conserve pas la valeur de retour ; la branche non-safe de la macro BROTLI_SAFE se contente également d'appeler la fonction et d'en jeter le résultat. (Analyse de SonicWall)DecodeLiteralBlockSwitch). Bien que les fonctions pointées diffèrent selon les analyses, la description du correctif de distribution (TuxCare) indique que les trois décodeurs de changement de bloc — littéral, commande et distance — ont été modifiés pour renvoyer un code d'erreur ; les trois chemins peuvent donc être considérés comme concernés.En conséquence, même lorsqu'une erreur de format survient, le décodeur continue comme si le changement avait réussi ; le compteur de longueur de bloc reste à 0 et l'état de position et de distance est reporté vers un chemin qui aurait dû être rejeté.