Ce qui se passe
En testant dix implémentations HTTP/3 pour son scanner TLS JA4Scan, FoxIO a trouvé le même défaut dans sept d'entre elles. Un client distant, sans compte, peut obliger un serveur à réserver bien plus de mémoire qu'il n'a reçu d'octets, jusqu'à épuiser ou figer un serveur laissé à ses réglages par défaut. Le dégât est un déni de service : aucune preuve de vol de données ni d'exécution de code, et aucune attaque dans la nature signalée. Un code de démonstration est public. HTTP/3 circule sur UDP, si bien que la requête arrive avant une bonne partie du filtrage habituel.
Le mécanisme
QPACK compresse les en-têtes de HTTP/3. Un champ courant devient une référence
d'un octet : l'en-tête strict-transport-security: max-age=31536000; includesubdomains; preload (71 octets) se réduit à 0xFA. La RFC 9114 (§4.2.2)
demande de plafonner la taille décodée, calculée avec 32 octets de surcoût
par champ. Les piles fautives plafonnent seulement la taille compressée, ou
décompressent tout avant de contrôler, ou oublient les 32 octets, ou laissent la
limite illimitée par défaut, ou ne l'appliquent jamais.
Deux variantes :
- L'accordéon : un bloc de 1 Mo compressé contient environ 160 000 en-têtes distincts. Sur quic-go, cela laisse environ 15 Mo en mémoire (une quinzaine de fois l'envoi ; l'avis de quic-go avance jusqu'à 50 fois).
- La table dynamique : une entrée d'environ 4 Kio est stockée une fois, puis référencée des milliers de fois par des références d'un octet, chacune reconstruisant l'entrée complète (rapport 4064:1). FoxIO mesure 600 à 1 800 fois sur lsquic et environ 4 000 fois sur Bun.
Bun cumule un second défaut : son serveur HTTP/3, que sa documentation qualifie d'expérimental, remplace le plafond de lsquic par un contrôle par en-tête, sans cumul. Au-delà de 2 Gio décodés, un compteur sur 32 bits retombe à zéro et le serveur tourne en boucle : un flux d'environ 516 Kio le laisse à 100 % de processeur, sans reprise.
État des correctifs
| Pile | État | Version corrigée | Identifiant |
|---|---|---|---|
| quic-go | corrigé | 0.57.0 | CVE-2025-64702 |
| Cloudflare quiche | corrigé | 0.29.3 | CVE-2026-12523 |
| lsquic | corrigé | 4.9.0 | aucun |
| Wireshark | corrigé | 4.6.2 / 4.4.12 | CVE-2025-13945 |
| Bun (testé en 1.4.3) | non corrigé | — | aucun |
| h3 (hyperium, Rust) | non corrigé | — | aucun |
| aioquic / mitmproxy | non corrigé | — | aucun |
IIS, Envoy, ngtcp2/nghttp3 et le quiche de Google ne sont pas touchés : ils plafonnent pendant le décodage. Le cas de Wireshark est distinct : son dissecteur HTTP/3 plante à l'ouverture d'une capture déchiffrée, ce n'est pas un serveur exposé. Les notes de Bun 1.4.4 (22 octobre) ne mentionnent pas de correctif QPACK.
Comment s'y prendre
- Caddy, Traefik, cloudflared reposent sur quic-go : prendre une version qui embarque quic-go 0.57.0 ou plus, en le vérifiant dans ses notes de version.
- LiteSpeed et OpenLiteSpeed : lsquic 4.9.0 ou plus.
- Bun : ne pas exposer de serveur HTTP/3.
- mitmproxy :
--set http3=false. - h3 (Rust) : fixer une valeur raisonnable à
max_field_section_size. - Piste hors étude : tant qu'une pile n'est pas corrigée, retirer l'annonce HTTP/3 ou fermer UDP/443 renvoie les clients sur HTTP/2.
Source : The Hacker News, 22 octobre 2026, d'après l'étude de FoxIO (billet daté du 20 octobre). Source en anglais.