Analyse post-incident de la panne du 18 novembre 2025 chez Cloudflare
(blog.cloudflare.com)- Le 18 novembre 2025 à 11:20 (UTC), la fonction essentielle d’acheminement du trafic du réseau Cloudflare a été interrompue, entraînant l’affichage de pages d’erreur pour des utilisateurs dans le monde entier
- La cause est l’augmentation anormale de la taille d’un « fichier de features » du système Bot Management à la suite d’un changement de permissions de base de données, sans lien avec une cyberattaque
- Cette augmentation de taille a fait que le logiciel de routage du trafic a dépassé sa limite et a échoué, provoquant à grande échelle des erreurs HTTP 5xx
- Vers 14:30, le déploiement du fichier problématique a été arrêté et remplacé par la version précédente saine, ce qui a permis de rétablir le trafic essentiel ; tous les services sont revenus à la normale à 17:06
- Cloudflare qualifie cet incident de pire panne depuis 2019 et met en place des mesures de prévention, notamment un renforcement de la validation des fichiers de configuration et l’introduction d’un kill switch global
Vue d’ensemble de la panne
- Vers 11:20, un échec de l’acheminement du trafic essentiel s’est produit sur le réseau Cloudflare ; les utilisateurs voyaient des pages d’erreur internes de Cloudflare
- Ni cyberattaque ni acte malveillant n’étaient en cause ; la cause directe était un changement de permissions dans le système de base de données
- Ce changement a entraîné un doublement de la taille du « fichier de features » utilisé par le système Bot Management, puis sa diffusion sur l’ensemble du réseau
- Lorsque le logiciel de routage du trafic a lu ce fichier, la limite de taille autorisée a été dépassée, provoquant une erreur système
- Au départ, l’incident a été pris pour une attaque DDoS de grande ampleur, puis, une fois la cause identifiée, le fichier a été remplacé par la version précédente saine pour lancer la reprise
Déroulement et impact de la panne
- Avant 11:20, le taux d’erreurs 5xx était normal, puis il a brusquement augmenté après le déploiement du mauvais fichier de features
- Sur certains nœuds du cluster de base de données ClickHouse, des résultats de requête incorrects étaient générés toutes les 5 minutes ; des fichiers sains et défectueux étaient déployés en alternance, ce qui faisait osciller le système entre reprise et échec
- À partir de 14:30, la génération du fichier problématique a été arrêtée et un fichier sain a été injecté manuellement, avec reprise via redémarrage du proxy central
- À 17:06, tous les services étaient revenus à la normale
| Service | Impact |
|---|---|
| Core CDN et services de sécurité | Erreurs HTTP 5xx |
| Turnstile | Échec de chargement, connexion impossible |
| Workers KV | Forte hausse des erreurs 5xx due à l’échec de la gateway |
| Dashboard | Connexion impossible à cause de la panne de Turnstile |
| Email Security | Baisse temporaire de la précision de détection du spam, échec de certains déplacements automatiques |
| Access | Multiples échecs d’authentification, sessions existantes conservées |
- Pendant l’incident, la latence des réponses CDN a augmenté, en raison d’une forte hausse de l’utilisation CPU des systèmes de débogage
Cause de la panne : système Bot Management
- Le module Bot Management de Cloudflare utilise des modèles de machine learning pour produire un score de bot pour chaque requête
- Le fichier de configuration des features utilisé en entrée du modèle est diffusé sur l’ensemble du réseau toutes les quelques minutes pour répondre aux menaces les plus récentes
- Une modification du comportement d’une requête ClickHouse a provoqué l’inclusion de nombreuses lignes de features dupliquées, augmentant la taille du fichier
- Cela a provoqué une erreur dans le module Bot Management, qui a alors renvoyé des réponses HTTP 5xx, avec des répercussions aussi sur Workers KV et Access
- Sur le nouveau moteur proxy FL2, cela a produit des erreurs 5xx ; sur l’ancienne version FL, le score de bot était fixé à 0, augmentant les faux positifs
Changement de comportement des requêtes ClickHouse
- À 11:05, déploiement d’un changement des permissions d’accès à la base de données de ClickHouse
- Auparavant, seules les métadonnées de la base
defaultpouvaient être consultées ; après ce changement, celles de la baser0sont aussi devenues visibles - La requête de génération du fichier de features de Bot Management s’exécutait sans filtre sur le nom de la base de données, ce qui a conduit au retour de colonnes en doublon
- En conséquence, le nombre de lignes du fichier de features a plus que doublé, dépassant les limites du système
Préallocation mémoire et panic système
- Le module Bot Management applique une limite maximale de 200 features de machine learning et préalloue la mémoire en conséquence
- Le fichier erroné incluait plus de 200 features, déclenchant un panic dans le code Rust, avec l’erreur
thread fl2_worker_thread panicked: called Result::unwrap() on an Err value - Cela a entraîné une forte vague d’erreurs HTTP 5xx
Autres impacts et processus de reprise
- Workers KV et Access dépendaient du proxy central, ce qui a amplifié l’impact de la panne
- À 13:04, un correctif a permis à Workers KV de contourner le proxy, réduisant le taux d’erreur
- Dashboard dépendait de Turnstile et de Workers KV, rendant la connexion impossible
- Deux baisses de disponibilité ont eu lieu, de 11:30 à 13:10 puis de 14:40 à 15:30
- Les files d’attente et les requêtes de nouvelle tentative ont accru la latence, avant un retour à la normale vers 15:30
- Après 14:30, la majorité des services ont retrouvé un fonctionnement normal, puis la reprise complète a été atteinte à 17:06
Mesures de prévention
- Renforcement de la validation des entrées des fichiers de configuration générés par Cloudflare
- Extension des kill switches globaux de fonctionnalités
- Prévention de l’épuisement des ressources système causé par le reporting d’erreurs
- Révision des conditions d’erreur dans l’ensemble des modules du proxy central
Résumé de la chronologie (UTC)
| Heure | État | Description |
|---|---|---|
| 11:05 | Normal | Déploiement du changement de contrôle d’accès à la base de données |
| 11:28 | Début de l’impact | Premières erreurs observées sur le trafic client |
| 11:32–13:05 | Enquête en cours | Analyse de la cause des erreurs Workers KV, tentatives d’atténuation |
| 13:05 | Impact réduit | Mise en place du contournement pour Workers KV et Access |
| 13:37 | Reprise ciblée | Préparation du rollback du fichier de configuration Bot Management |
| 14:24 | Arrêt du déploiement du fichier problématique | Validation terminée du fichier sain |
| 14:30 | Impact principal résorbé | Déploiement global du fichier sain, début de la reprise des services |
| 17:06 | Reprise complète | Tous les services sont revenus à la normale |
Conclusion
- Cette panne est due à l’interaction entre la logique de génération du fichier de configuration de Bot Management et un changement de permissions de base de données
- Cloudflare la considère comme la panne réseau la plus grave depuis 2019
- L’entreprise prévoit des améliorations structurelles pour renforcer la résilience du système ainsi que des mécanismes de défense automatisés
8 commentaires
Les incidents liés aux fichiers de configuration surviennent partout.
Quand Cloudflare est tombé, toutes sortes de services se sont arrêtés, c’était l’enfer...
Le document d’analyse des causes a été publié assez rapidement, dis donc.
Au fait, l’auteur de cet article était le CEO.
Réactions sur Hacker News
C’est un incident à plusieurs millions de dollars causé par un .unwrap()
Appeler
.unwrap()sur un chemin d’infrastructure critique d’Internet revient à déclarer : « ça ne peut absolument pas échouer, et si ça échoue, on tue immédiatement le thread ».Le compilateur Rust force à exprimer explicitement la possibilité d’un échec, mais ici ils ont choisi le panic au lieu de le gérer proprement.
À mon avis, c’est un cas typique d’antipattern parse, don’t validate.
.unwrap(). C’est peut-être parce qu’on le voit souvent dans les exemples de code.Dans du vrai code d’exploitation,
.unwrap()ou.expect()devraient être revus comme des panic.Si on utilise
.unwrap()en production, il faut obligatoirement un commentaire « INFALLIBILITY », et on peut l’imposer avecclippy::unwrap_used.Ce n’est pas simplement à cause de
.unwrap(), mais aussi parce que la requête ne séparait pas les bases de données, ce qui a grossi le payload, et parce que ClickHouse exposait davantage de bases.Plutôt que de conclure « c’est la faute de unwrap », je pense qu’il est plus important d’améliorer la conception pour éviter qu’un kill switch global ou qu’un composant n’épuise les ressources système.
La couche FL2 devrait intercepter les panic de chaque composant, mais le fail-open n’est pas toujours préférable.
Il faudrait ajouter une logique permettant de décider explicitement au niveau FL2 s’il faut intercepter et traiter un panic.
Dans un système shardé, je me demande aussi pourquoi il n’y avait ni déploiement progressif ni monitoring.
!et le déballage explicite avec?.Je n’utilise presque jamais le déballage implicite. Même pour une valeur garantie, je la traite toujours explicitement.
Par exemple, je définirais
@IBOutlet weak var someView?plutôt que@IBOutlet weak var someView!.C’est une approche ceinture et bretelles.
Publier un post mortem moins de 24 heures après la panne, c’est vraiment impressionnant.
Dans la plupart des grandes entreprises, la publication du code serait presque impossible à cause des validations de multiples stakeholders.
En lisant l’explication de Cloudflare sur la panne, je me suis demandé : « pourquoi la restauration a-t-elle pris autant de temps ? »
J’ai compris la cause de la panne, mais si la majeure partie du réseau est tombée, on pourrait penser que revenir sur le dernier changement de configuration est la priorité absolue.
Bien sûr, c’est évident après coup, mais le fait qu’ils aient commencé l’enquête en 7 minutes est impressionnant.
Cet incident rappelle l’accident CrowdStrike.
Un fichier de configuration généré automatiquement a cassé le logiciel, puis a été propagé à l’ensemble du réseau.
Je comprends qu’il faille pouvoir déployer vite, mais cette affaire révèle l’absence de déploiement progressif et de stratégie de rollback.
Quand on regarde le plan d’amélioration annoncé par Cloudflare :
figurent bien dans la liste.
Mais il manque les déploiements canary ou les déploiements progressifs de configuration.
Un switch global peut être dangereux, et un seul bug peut arrêter tout le système.
Je me demande aussi pourquoi ClickHouse a été utilisé comme magasin de feature flags. La documentation ClickHouse sur la déduplication mentionne elle aussi des risques.
Une cartographie des dépendances entre services rendrait aussi la recherche de la cause bien plus simple.
Les déploiements de code sont prudents, mais pas les déploiements de configuration. Il faut considérer que la configuration est aussi du code.
Le passage indiquant que la page de statut est tombée et qu’ils ont cru à une attaque est intéressant.
Ils disent qu’elle est totalement séparée de l’infrastructure Cloudflare, mais rien n’explique pourquoi elle est tombée elle aussi.
J’ai intégré Turnstile avec une stratégie fail-open, et cela a aidé pendant cette panne.
Si le JS ne se charge pas, j’autorise l’envoi avec un jeton factice, et côté backend, si la validation échoue, je traite aussi en fail-open.
Certains utilisateurs ont quand même été bloqués, mais l’impact global a été réduit.
C’est une approche rendue possible par d’autres mesures d’atténuation contre les bots.
Mais cela ne semble fonctionner que si l’attaque n’est pas ciblée.
Je me demande pourquoi Cloudflare autorisait
.unwrap()dans son code.À minima, ils auraient dû utiliser
expect("cela ne devrait jamais arriver").La philosophie consistant à traiter les erreurs comme des valeurs est précisément censée éviter ce genre de problème, et cela aurait rendu le diagnostic bien plus facile.
Dans du code impliquant des appels réseau, il y a bien trop de possibilités d’échec.
J’utilise
.unwrap()pendant le développement, mais en production il m’arrive de laisser des expect(), parce qu’il n’y a parfois tout simplement plus aucun moyen d’aller plus loin.La vraie leçon, c’est que trop de fonctionnalités dépendent d’un petit nombre d’acteurs.
La logique du winner-takes-all s’accentue, et la résilience du système en souffre.
Bien sûr, ils ont mérité leur position, mais attendre d’Internet qu’il soit toujours « en état de marche » me paraît excessif.
Dire que « Rust rend tout sûr » est exagéré.
Quel que soit le langage, mal l’utiliser revient à braquer l’arme sur son propre pied.
Même une entreprise comme CF utilise
.unwrap()… wow. Comment ce code a-t-il pu être déployé en production ?On dirait que
unwrapn’est pas le problèmeLe problème fondamental, c’est la requête erronée.
Mais je pense aussi que le fait d’avoir sauté la validation du problème avec
unwrapest en soi un problème.Même si un souci survenait en interne, si l’erreur avait été gérée, le trafic ne serait sans doute pas tombé.