Ce qui s'est passé
Entre le 27 août et le 9 septembre 2026, des clients de Workers AI qui
interrogeaient le modèle @cf/zai-org/glm-5.3 ont reçu des réponses contenant
des données d'autres clients, venues de requêtes faites juste avant les leurs.
Cloudflare compte 155 réponses touchées, toutes pour des prompts de plus de
681 280 tokens. Aucun autre modèle de la plateforme n'était concerné.
Les requêtes concernées correspondent, par leur rythme et leur volume, à un usage normal en contexte long, pas à quelqu'un qui exploiterait la faille. Cloudflare dit n'avoir trouvé aucune preuve d'exploitation délibérée.
Deux défauts qui s'additionnent
1. Une configuration. GLM 5.3 était déployé avec un contexte de 1 048 576 tokens, mais le pool du cache KV des GPU de prefill, dimensionné au démarrage par SGLang avec la mémoire restante après le chargement des poids, n'atteignait que 681 280 tokens. Cloudflare connaissait cet écart. L'équipe comptait sur une erreur du moteur pour tout prompt trop long, et ses tests de contexte long renvoyaient des réponses réussies : elle ne vérifiait que les codes HTTP et les performances, pas le contenu des sorties.
2. Un bug de SGLang en mode désagrégé (prefill et décodage sur des GPU distincts, le cache passant de l'un à l'autre par RDMA via Mooncake). Un prompt trop long était marqué rejeté et remplacé par un jeton factice, mais les files d'admission vérifiaient si la requête était terminée, pas rejetée : elle passait donc pour vivante.
Le décodage avait réservé les pages pour tout le prompt ; une seule avait été écrite par cette requête. Il générait en lisant aussi les autres, qui contenaient encore les prompts et les générations partielles de clients précédents. Côté client : un statut 200 au lieu d'un 400, un nombre de tokens de prompt exact, une réponse cohérente, et plus rapide que ne le permettait un vrai prefill.
Les pages du cache ne sont pas remises à zéro entre deux requêtes : c'est courant dans les moteurs d'inférence et nécessaire aux meilleures performances, mais cela laisse au moteur seul la charge de savoir à qui appartient chaque page.
Chronologie (UTC)
- 8 septembre, 23:11 : signalement par Gadi Evron (Knostic) via HackerOne.
- 9 septembre, 13:22 : incident déclaré, fuite reproduite avec deux comptes en 25 minutes ; 14:00 : modèle rendu privé (HTTP 400).
- 9 septembre, 14:52 : tous les nœuds de prefill passent à la configuration corrigée ; 19:40 : modèle rétabli, avec un correctif de moteur.
Ce que Cloudflare a changé
- Pool de prefill porté à environ 2,04 millions de tokens, soit près de deux fois le contexte : un prompt valide tient toujours.
- Moteur corrigé pour qu'une requête rejetée soit retirée de la file d'admission
avant tout transfert (PR SGLang
#38704, proposée par Cloudflare ;#36988et#38935, fusionnées). - Contrôle ajouté à chaque changement de déploiement désagrégé : taille du pool KV contre longueur de contexte, libération différée sur les deux rôles, lots de transfert bornés dans le délai de libération, correctifs appliqués.
- Option SGLang
--disaggregation-enable-kv-checksum(PR#39500, v0.5.21) : le décodage vérifie une somme de contrôle du cache transféré.
Le bug avait été signalé à SGLang le 6 juillet (issue #30233). Le correctif est
sorti en v0.5.20, complété en v0.5.21 (2 octobre) et v0.5.22
(19 octobre).
Comment s'y prendre
- Si vous exploitez SGLang en désagrégé, passez en 0.5.22 ou plus.
- Au démarrage, lisez la taille du pool KV choisie (affichée dans les journaux, exposée en métrique) et comparez-la au contexte annoncé.
- Testez les prompts longs en vérifiant le contenu des réponses, pas seulement le statut HTTP et la latence.
Source : Cloudflare, 26 octobre 2026. Source en anglais.