Brotli CVE-2026-111497 : corriger Node.js, Bun et Python

Brotli CVE-2026-111497 : corriger Node.js, Bun et Python

Brotli CVE-2026-111497 : corriger Node.js, Bun et Python

CVE-2026-111497 est une corruption de mémoire dans le décodeur Brotli de Google, le code C qui décompresse les données Content-Encoding: br. Des données compressées forgées écrivent au-delà de la fin d'un tampon, ce qui peut faire planter le programme, divulguer de la mémoire ou exécuter le code de l'attaquant. Node.js, Bun, les paquets Python Brotli et brotlicffi ainsi qu'Envoy embarquent chacun leur propre copie de ce décodeur : chacun doit donc être mis à jour séparément. Ce guide montre quand une application est réellement exposée, comment vérifier un serveur en une commande et comment déployer le correctif sans oublier un seul conteneur.

Quelle gravité

  • Google la note 9.2 (critical) en CVSS 4.0, Node.js la classe high, Red Hat lui donne 8.1.
  • Les chercheurs d'Imperva ont exécuté leur propre code sur un Node.js 24.22.0 non corrigé sous Linux ARM64, à la fois via une réponse récupérée par fetch et via le corps d'une requête Express. L'exploit n'est pas public.
  • L'évaluation de la CISA du 23 octobre ne relevait aucune exploitation active, et il n'existe pas de preuve de concept publique fiable.
  • La faille fonctionne dans les deux sens : un serveur qui décompresse des entrées compressées peut être attaqué par un client, et un client qui décompresse des réponses compressées peut être attaqué par un serveur.

Le correctif a été intégré au code source de Brotli le 27 février, mais aucune version de Brotli ne l'a contenu avant le 21 octobre, d'où la sortie de tous les runtimes corrigés la même semaine.

Êtes-vous exposé ?

Seul le code qui décode des données Brotli contrôlées par quelqu'un d'autre est concerné :

  • Node.js et Bun - le fetch() intégré lorsqu'il lit une réponse envoyée avec Content-Encoding: br, les appels Brotli de node:zlib sur des données non fiables et les parseurs de corps qui décompressent des envois Brotli (Express 5, body-parser 2). Un simple serveur HTTP Node.js ne décode pas les corps de requête de lui-même.
  • Python - il suffit que le paquet Brotli ou brotlicffi soit installé : requests, urllib3, httpx et aiohttp décodent alors eux-mêmes les réponses Brotli, même si votre code n'importe jamais Brotli.
  • Envoy et Istio - uniquement si un filtre de décompression Brotli est configuré.

Tout service qui appelle des API tierces, des webhooks, des prestataires de paiement ou qui scrape des pages exécute fetch() vers des serveurs que vous ne contrôlez pas. Retirer br de Accept-Encoding n'est pas un correctif : un serveur peut quand même envoyer du Brotli.

Logiciel Versions touchées Corrigé en
Node.js 22.x, 24.x, 26.x avant le correctif ; 20.x et antérieures (fin de vie) 22.23.4, 24.22.1, 26.12.1
Bun 1.4.3 et antérieures 1.4.4
Python Brotli 1.2.0 et antérieures 1.2.1
Python brotlicffi 1.2.0.x et antérieures 1.2.1.0
Google Brotli (bibliothèque C) 1.0.3 - 1.2.0 1.0.10, 1.1.1, 1.2.1
Envoy 1.39.2, 1.38.5, 1.37.7, 1.36.11 1.40.0, 1.39.3, 1.38.6, 1.37.8, 1.36.12
Istio 1.31.0 - 1.31.1, 1.30.0 - 1.30.5, 1.29.0 - 1.29.8 1.31.2, 1.30.6, 1.29.9

Vérifier un serveur en une commande

Ce script shell POSIX examine Bun, Node.js et Python sur la machine (ou dans un conteneur) et indique lesquels sont antérieurs au correctif. Enregistrez-le sous brotli-check.sh :

#!/bin/sh
# CVE-2026-111497 (Brotli decoder): which runtimes on this host are older than the fixes?
ver_lt() { [ "$1" = "$2" ] && return 1; [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]; }
if command -v bun >/dev/null 2>&1; then
  v=$(bun --version)
  if ver_lt "$v" 1.4.4; then echo "bun $v: VULNERABLE, upgrade to 1.4.4+"; else echo "bun $v: fixed"; fi
fi
if command -v node >/dev/null 2>&1; then
  v=$(node -p "process.versions.bun ? '' : process.versions.node")
  if [ -z "$v" ]; then echo "node: this is Bun's node shim, see the bun line"; else major=${v%%.*}
  case $major in
    22) fix=22.23.4 ;; 24) fix=24.22.1 ;; 26) fix=26.12.1 ;;
    *) fix= ;;
  esac
  if [ -z "$fix" ]; then echo "node $v: no fixed release for this line, move to 22, 24 or 26"
  elif ver_lt "$v" "$fix"; then echo "node $v: VULNERABLE, upgrade to $fix+"
  else echo "node $v: fixed"; fi
  fi
fi
for py in python3 python; do
  command -v $py >/dev/null 2>&1 || continue
  $py - <<'PY'
from importlib import metadata
for pkg, fix in (("Brotli", "1.2.1"), ("brotlicffi", "1.2.1.0")):
    try:
        v = metadata.version(pkg)
    except metadata.PackageNotFoundError:
        print(f"python {pkg}: not installed")
        continue
    a = [int(x) for x in v.split(".") if x.isdigit()]
    b = [int(x) for x in fix.split(".")]
    print(f"python {pkg} {v}: {'VULNERABLE, upgrade to ' + fix + '+' if a < b else 'fixed'}")
PY
  break
done
sh brotli-check.sh
docker exec my-app sh -s < brotli-check.sh   # the same check inside a running container

Sortie vérifiée le 2026-10-24 (un portable de développeur, puis les images Docker officielles) :

bun 1.4.1: VULNERABLE, upgrade to 1.4.4+
node 26.6.0: VULNERABLE, upgrade to 26.12.1+
python Brotli: not installed
python brotlicffi: not installed
bun 1.4.4: fixed
node: this is Bun's node shim, see the bun line
node 22.23.4: fixed
node 16.20.2: no fixed release for this line, move to 22, 24 or 26
python Brotli 1.1.0: VULNERABLE, upgrade to 1.2.1+
python brotlicffi: not installed

Lancez-le dans chaque conteneur, pas seulement sur l'hôte : le Node.js de l'hôte ne dit rien de celui qui est intégré à une image.

Déployer le correctif

  1. Trouvez chaque copie. Les images sont l'oubli le plus courant. Listez ce qui tourne : docker ps --format '{{.Image}}', puis les lignes FROM de vos Dockerfiles. Un tag comme node:22 ou oven/bun:alpine n'avance que lorsque vous faites un pull ; un tag figé comme oven/bun:1.4.1-slim n'avance jamais.
  2. Mettez à jour le runtime. Montez les tags figés (oven/bun:1.4.4-slim, node:22.23.4-alpine), lancez bun upgrade et mettez à jour vos paquets Node.js sur les hôtes, et pip install -U "Brotli>=1.2.1" (ou brotlicffi>=1.2.1.0) dans les environnements Python. Si une application Python n'a pas besoin de Brotli, pip uninstall Brotli brotlicffi ferme aussi la voie : les clients HTTP se rabattent sur gzip et deflate.
  3. Reconstruisez et remplacez. docker compose build --pull && docker compose up -d. Un processus en cours garde l'ancien décodeur jusqu'à son redémarrage, donc redémarrez aussi les services sur les hôtes.
  4. Vérifiez. Relancez le script de vérification dans chaque conteneur (docker exec <name> bun --version en est la version rapide). Les lockfiles avec --frozen-lockfile peuvent faire échouer la reconstruction après une mise à jour des dépendances : commitez le lockfile mis à jour avec package.json.
  5. Impossible de mettre à jour tout de suite ? Rejetez au proxy les requêtes avec Content-Encoding: br avant que quoi que ce soit ne décode le corps, et évitez de récupérer des données depuis des hôtes non fiables. Vercel rappelle que les règles de pare-feu ne couvrent pas les réponses que votre propre code récupère d'autres serveurs - seule la mise à jour le fait.

Pour une stack Node.js sur une VM, voir Serveur cloud pour Node.js, pour Python Serveur cloud pour Python et Flask, et pour des images qui se reconstruisent proprement Serveur cloud pour Docker Swarm.

Ce que nous avons fait

Dans les jours qui ont suivi les correctifs, nous avons passé en 1.4.4 chaque service DCXV qui tourne sous Bun : les images de base figées sont passées à des tags corrigés, et toutes les images ont été reconstruites avec un pull frais. Nos composants Node.js ne décodent pas de corps Brotli, et nos proxys n'ont pas de décompression Brotli. Les serveurs clients sont gérés par leurs propriétaires : si vous faites tourner Node.js, Bun ou Python sur un serveur cloud DCXV, lancez la vérification ci-dessus dès aujourd'hui, ou demandez-nous notre offre d'administration de serveur infogérée.

Sources (vérifiées le 2026-10-24) : les versions de sécurité Node.js d'octobre 2026 (22.23.4, 24.22.1, 26.12.1), la version Bun 1.4.4, l'évaluation de la CISA du 23 octobre 2026 et les recherches d'Imperva.

Starlink Mini 2 derrière CGNAT : joindre un site qui bouge
networkingcloudinfrastructure

Starlink Mini 2 derrière CGNAT : joindre un site qui bouge

La Starlink Mini 2 arrive, mais les offres standard sont derrière un CGNAT. 990 208 IPv4 pour 12 M+ de clients : nous comparons quatre accès à un site.

Transferts IPv4 LACNIC 2026 : règles, frais, un an de blocage
ipv4transfernetworking

Transferts IPv4 LACNIC 2026 : règles, frais, un an de blocage

Transferts IPv4 chez LACNIC en 2026 : règles de la section 2.3.2.18, frais de US$ 1,037, NIC.br et NIC México, et notre décompte de 1,929 transferts de 2016 à 2026.

Data centers : la contestation gagne l'Europe, que faire
clouddedicatedinfrastructure

Data centers : la contestation gagne l'Europe, que faire

Le 6 novembre, des centaines de personnes sont entrées sur le chantier Microsoft d'Amsterdam. Les chiffres du réseau, la latence mesurée et que faire.

Data centers rejetés 45 à 1 aux USA : leçons pour l'acheteur
clouddedicatedinfrastructure

Data centers rejetés 45 à 1 aux USA : leçons pour l'acheteur

47 scrutins locaux sur les data centers aux USA, le camp restrictif gagne 45 fois. Nous recomptons les données brutes : l'enjeu pour qui loue des serveurs.

AWS BYOIP en 2026 : $43.80 par IPv4 ou votre propre /24
ipv4pricingcloud

AWS BYOIP en 2026 : $43.80 par IPv4 ou votre propre /24

AWS facture $0.005 de l'heure par IPv4 publique, $43.80 par an. BYOIP échappe à ce coût : quand un /24 acheté ou loué est rentable, avec un contrôle de ROA.