CVE-2026-111497 : une faille dans le décodeur Brotli affecte Node.js, Bun, Python, .NET et Envoy — ce que vous devez mettre à jour maintenant
Une erreur dans le décodeur Brotli de Google (versions 1.0.3 à 1.2.0) permet, au moyen de données forgées, une écriture hors limites pouvant aller jusqu’à l’exécution de code (CVE-2026-111497, CVSS 9.2). Tout logiciel qui décompresse des données Brotli provenant de sources externes est concerné : Node.js, Bun, Python avec Brotli/brotlicffi, .NET, Envoy, curl. Des mises à jour sont disponibles.
Le décodeur Brotli de Google contient, dans les versions 1.0.3 à 1.2.0, une erreur qui permet à des données Brotli forgées d’écraser de la mémoire hors d’un tampon. La faille porte l’identifiant CVE-2026-111497 et une note de 9.2 selon CVSS 4.0 ; elle est connue publiquement sous les noms Node2Shell et Broccoli2Shell. Les conséquences possibles sont un plantage, la lecture de la mémoire du processus ou l’exécution de code. Imperva a démontré l’exécution de code sur un Node.js 24.22.0 non modifié. Du code de preuve de concept est en partie public, mais aucune attaque active n’est connue à ce jour. Node.js a publié les correctifs le 21 octobre 2026, les autres écosystèmes ont suivi jusqu’au 26 octobre.
Après cette annonce, j’ai vérifié mes propres systèmes : le runner de build de ce site utilisait encore Node.js 22.23.1, alors que la version 22.23.4 était disponible depuis plusieurs jours. La raison est expliquée dans la section consacrée à GitHub Actions plus bas ; elle concerne tous les runners auto-hébergés utilisant actions/setup-node.
Assistance pour l’inventaire et les mises à jour
Si vous avez besoin d’aide pour identifier les composants concernés dans des applications, des images de conteneur ou des pipelines CI, utilisez le formulaire de contact sur adeptio.ch. Je vous répondrai également à court terme.
Cause
L’erreur se situe dans la fonction DecodeBlockTypeAndLength(). Elle traite les changements de bloc dans le flux de données compressé, c’est-à-dire les emplacements où le décodeur passe à un autre code Huffman. Dans les versions vulnérables, la fonction ne renvoie qu’une valeur booléenne ; BROTLI_FALSE signifie à la fois « flux de données incorrect » et « entrée supplémentaire nécessaire ». Un flux forgé déclare un seul type de bloc et épuise sa longueur, forçant ainsi un changement qui ne peut pas réussir. Le décodeur interprète cela comme une entrée manquante, ajoute des octets supplémentaires à un tampon interne de 8 octets et écrit ainsi au-delà de sa fin.
Le correctif upstream (commit 0ed4268 dans le dépôt google/brotli) introduit un code d’erreur distinct BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH et interrompt le décodage. OpenAI Codex Security avait déjà signalé l’erreur en février 2026. Le correctif avait alors été intégré au code source, mais n’avait pas été considéré comme une correction de sécurité et n’était apparu dans aucune version. Il n’a été livré qu’avec Brotli 1.2.1 et les versions de Node.js du 21 octobre 2026.
Quand un système est vulnérable
Compresser avec Brotli ne présente aucun risque ; seuls sont vulnérables ceux qui décompressent des données Brotli provenant d’une source externe. Il existe deux directions :
- Client : l’application récupère une URL et décode une réponse avec
Content-Encoding: br. Lefetch()intégré de Node.js et Bun le fait automatiquement et ne peut pas être désactivé. Sont donc concernés les crawlers, les récepteurs de webhooks avec rappel, les aperçus de liens, les scripts de surveillance et toute automatisation qui charge du contenu depuis des serveurs tiers. Pour cela, il suffit à un attaquant de contrôler l’un des serveurs interrogés. - Serveur : un framework ou un middleware décompresse des corps de requête avec
Content-Encoding: br. Imperva cite pour Node.jsbody-parser2.0.0 à 2.3.0 et Express 5.0.0 à 5.3.0 avec des parseurs configurésjson()ouraw(). Un serveurhttpNode.js nu ne décode pas lui-même les corps entrants.
Apache mod_brotli et les modules Brotli répandus pour nginx ne font que compresser et ne sont donc pas concernés. Envoy et Istio ne sont vulnérables que si le filtre de décompression Brotli est configuré ; Istio ne l’active pas par défaut.
Composants concernés et versions corrigées
| Composant | Versions corrigées | Remarque |
|---|---|---|
| libbrotli (Google Brotli) | 1.2.1, 1.1.1, 1.0.10 | les versions 1.0.3 à 1.2.0 sont concernées |
| Node.js | 26.12.1, 24.22.1, 22.23.4 | version du 21.10.2026, contient d’autres correctifs (DNS, vérification des noms TLS) |
| Bun | 1.4.4 | reconstruire les exécutables créés avec bun build --compile |
Python Brotli | 1.2.1 | utilisé automatiquement par urllib3, requests et aiohttp lorsqu’il est installé |
Python brotlicffi | 1.2.1.0 | idem ; également comme extra httpx[brotli] |
| .NET | 8.0.33, 9.0.22, 10.0.14, 11 RC3 | mise à jour hors bande du 25.10.2026 ; .NET Framework n’est pas concerné, .NET 7 n’a pas de correctif |
| Envoy | 1.40.0, 1.39.3, 1.38.6, 1.37.8 | uniquement avec le filtre de décompression Brotli |
| Istio | 1.31.2, 1.30.6, 1.29.9 | uniquement avec un décompresseur Brotli dans un EnvoyFilter |
| Java brotli4j | 1.24.0 | le wrapper JNI embarque sa propre copie de Brotli |
| curl/libcurl | compilation avec Brotli 1.2.1 | uniquement avec --compressed ou CURLOPT_ACCEPT_ENCODING |
Les autres bindings pour PHP, Ruby et Go (cgo) dépendent de la libbrotli du système ou embarquée. Parmi les distributions Linux, Debian 12 et 13, Alpine et Amazon Linux 2023 disposaient de paquets corrigés le 26 octobre ; Fedora et Red Hat étaient partiellement corrigés, tandis que le correctif était encore en attente pour Ubuntu et SUSE.
Trouver les versions concernées
Pour Node.js, Python et la bibliothèque système, trois commandes suffisent. Sous Windows, node -v donne le même résultat que sous Linux.
node -v
pip show Brotli brotlicffi
pipdeptree -r -p Brotli
Sous Debian/Ubuntu et Alpine, le gestionnaire de paquets affiche la version de la bibliothèque système :
dpkg -l 'libbrotli*'
apk info -v brotli-libs
Les images de conteneur doivent être vérifiées séparément : un hôte mis à jour ne sert à rien si l’image contient une ancienne version de Node.js ou une libbrotli embarquée. Après la mise à jour, les images doivent être reconstruites et les workloads en cours redémarrés ; pour Bun et brotli4j, cela s’applique également aux applications qui lient Brotli statiquement.
Runners GitHub auto-hébergés : setup-node prend la version depuis le cache
actions/setup-node avec node-version: 22 ne vérifie pas par défaut si une version 22 plus récente existe. Si une version appropriée est déjà présente dans le cache d’outils du runner, elle est utilisée. Sur les runners hébergés par GitHub, l’image est régulièrement redéployée ; un runner auto-hébergé conserve en revanche son cache jusqu’à ce que quelqu’un le vide. Le journal indique alors par exemple Found in cache @ .../_tool/node/22.23.1/x64.
Une ligne supplémentaire dans chaque étape setup-node résout le problème :
- uses: actions/setup-node@v4
with:
node-version: 22
check-latest: true
Il est également possible d’indiquer explicitement la version minimale (node-version: 22.23.4) ; elle doit alors être mise à jour à chaque publication de sécurité. C’est particulièrement pertinent pour les pipelines qui récupèrent du contenu depuis des serveurs externes, tels que les scanners, les vérificateurs de liens ou les flux : fetch() y communique avec des serveurs que vous ne contrôlez pas, et le runner a généralement accès aux secrets de déploiement.
Si une mise à jour immédiate n’est pas possible
Les mesures d’atténuation agissent au niveau du décodage :
- Entrant : rejeter au niveau du proxy inverse ou du middleware les requêtes dont
Content-Encodingcontientbr. La comparaison doit ignorer la casse et couvrir également les listes telles quegzip, br. - Sortant : retirer
brdeAccept-Encodinget rejeter les réponses avecContent-Encoding: bravant le décodage. Le retirer uniquement deAccept-Encodingne suffit pas, car un serveur forgé peut tout de même envoyer cet encodage. Cela n’est pas possible avec lefetch()intégré de Node.js et Bun ; seule la mise à jour aide dans ce cas. - curl : omettre
--compressed; dans libcurl, laisserCURLOPT_ACCEPT_ENCODINGsurNULL. - Python : désinstaller
Brotlietbrotlicffi, et supprimer des dépendances les extras tels quehttpx[brotli]. urllib3, requests et aiohttp reviennent alors à gzip et deflate. - Envoy/Istio : supprimer le décompresseur Brotli de la configuration ou des EnvoyFilters et vérifier la configuration en cours d’exécution.
Cloudflare Workers et navigateurs
Les personnes qui exploitent des applications sous forme de Cloudflare Worker n’exécutent pas leur propre processus Node.js ; le runtime workerd est exploité et mis à jour par Cloudflare. Cloudflare n’avait pas publié de déclaration sur CVE-2026-111497 au 26 octobre ; les clients ne peuvent rien modifier dans le runtime lui-même. Les outils autour du Worker restent toutefois concernés : les scripts de build, wrangler et les environnements de développement locaux s’exécutent sur Node.js et devraient utiliser une version corrigée. Les navigateurs utilisent leurs propres implémentations de Brotli ; ils ne sont pas cités comme concernés dans les communications des éditeurs et des chercheurs en sécurité.
Chronologie
| Date | Événement |
|---|---|
| Février 2026 | OpenAI Codex Security signale l’erreur, le correctif arrive dans le code source de Brotli sans publication |
| 21.10.2026 | Node.js publie 26.12.1, 24.22.1 et 22.23.4 |
| 22.10.2026 | Brotli 1.2.1 et brotlicffi 1.2.1.0 sur PyPI ; analyse d’Imperva avec exécution de code |
| 23.10.2026 | Correctifs pour libbrotli, Bun, Envoy et Istio |
| 24.10.2026 | brotli4j 1.24.0, paquets pour Amazon Linux 2023 |
| 25.10.2026 | Mises à jour hors bande pour .NET |
| 26.10.2026 | Debian et Alpine corrigés, Fedora et Red Hat partiellement |
Commentaires
Les commentaires sont chargés depuis GitHub / Giscus.