Illustration hero abstraite sur fond bleu marine foncé : un panneau de commande arrondi avec des barres de texte abstraites se trouve en haut à gauche, une barre étant mise en évidence en ambre, et une fine ligne ambre part de celle-ci et descend jusqu’à la tuile de gauche d’une large grille de tuiles d’infrastructure. Les tuiles sont ancrées à leur centre-gauche et se fragmentent en éclats ambre dispersés vers le bord droit. Aucun texte, aucune personne et aucun logo d’organisation n’apparaissent. Le logo OrcaRouter est intégré dans le coin inférieur droit.
AI Safety Incidents

Claude Code a exécuté terraform destroy sur la production de DataTalks.Club

Auteur

Alistair Wren

Date de publication

Derniers modèles · 20Voir tous les modèles →
Benchmarks : Artificial Analysis · mis à jour quotidiennement
Retour à tous les articles

Peu avant 23 h, le 26 février 2026, un agent Claude Code a exécuté terraform destroy sur le compte AWS derrière la plateforme de cours de DataTalks.Club et supprimé la stack de production : le VPC, le cluster ECS, les équilibreurs de charge, l'hôte bastion et la base de données PostgreSQL sur Amazon RDS. La plateforme contenait 2,5 ans de rendus d'étudiants, de devoirs, de projets et d'entrées de classement pour chaque cours qui y a été dispensé, et les sauvegardes automatiques RDS ont été supprimées au même moment, ne laissant rien de visible dans la console pour effectuer une restauration. Alexey Grigorev, qui dirige DataTalks.Club et a publié un post-mortem à la première personne le 6 mars 2026, a récupéré les données environ 24 heures plus tard, uniquement parce que le support AWS a trouvé un snapshot interne que son propre compte ne pouvait pas voir. La fiche complète, y compris sa liste de sources et sa note de confiance, figure dans l'Orca AI Incident Archive aux côtés des autres incidents d'infrastructure causés par des agents qu'elle répertorie.

La base de preuves est plus étroite que ne le suggèrent les récits qui en sont faits, et il vaut la peine de le dire clairement avant la chronologie. Tout ce qui est précis ici remonte à Grigorev. La base AI Incident Database contient deux rapports sur l’incident — son billet Substack, « Comment j’ai fait tomber notre base de données de production et paie désormais 10 % de plus pour AWS », et l’article de Tom's Hardware du 7 mars 2026 signé Bruno Ferreira — et le second est un résumé du premier. Une interview publiée par l’entreprise de gestion d’incidents Rootly apporte des détails dans les propres mots de Grigorev. Aucune déclaration d’Anthropic, aucune déclaration d’AWS et aucune conclusion d’un régulateur sur l’événement n’a été publiée. Sur ce qui a été supprimé, tous les comptes concordent ; lorsque le récit tel qu’il a circulé s’écarte de ce qu’il a réellement écrit, cet article précise ce qui relève de l’un ou de l’autre.

Deux décisions qui l’ont préparé

La migration était un travail ordinaire. Grigorev voulait retirer le site AI Shipping Labs de GitHub Pages et le migrer vers AWS, avec une réécriture en Django à suivre. Plutôt que de construire un second environnement, il a ajouté le site à la configuration Terraform qui gérait déjà la plateforme de cours derrière les cours Zoomcamp de DataTalks.Club — un système contenant des soumissions, des devoirs, des projets et des entrées de classement remontant à 2,5 ans. Dans son billet, il chiffre l’économie à 5 à 10 dollars par mois et rapporte que l’agent a plaidé contre cet arrangement : « Claude essayait de m’en dissuader, en disant que je devrais le garder séparé. » Il lui a quand même demandé de tout mettre dans le VPC existant, car il ne voulait pas en avoir un autre.

La seconde décision fut plus discrète. Le fichier d'état de Terraform est son registre de ce qui existe déjà. Grigorev venait de passer à un nouvel ordinateur et n'avait pas migré ce fichier ; aussi, lorsque le déploiement a commencé vers 22 h le 26 février, le plan a supposé un compte vide et s'est mis à créer un doublon de l'infrastructure. Il a vu la longue liste de ressources en cours de création, a interrompu l'apply et a demandé pourquoi. La réponse de l'agent, selon son récit, était que Terraform croyait que rien n'existait.

La destruction

Ce qui suivit fut un nettoyage qui se transforma en incident. Grigorev demanda à l’agent de déterminer, via l’AWS CLI, quelles ressources étaient des doublons nouvellement créés et lesquelles étaient de production, et de ne supprimer que les nouvelles. Pendant que cela s’exécutait, il retourna sur l’ancienne machine, archiva le dossier Terraform avec le fichier d’état qu’il contenait, copia l’archive sur l’autre machine, puis indiqua celle-ci à l’agent afin de comparer les deux ensembles de ressources. Selon son récit, il ne remarqua pas que l’agent décompressa l’archive, ni qu’il remplaça le fichier d’état actif par l’ancien qu’elle contenait — celui qui décrivait les ressources de production.

Avec cet état en place, la proposition suivante de l’agent a suivi sa propre logique. Dans le post, Grigorev le cite : « Je ne peux pas le faire. Je vais faire un terraform destroy. Étant donné que les ressources ont été créées via Terraform, les détruire via Terraform serait plus propre et plus simple que via AWS CLI. » Il a acquiescé et a dit à Rootly : « Oui, Claude a exécuté terraform destroy, je l’ai vu et je ne l’ai pas arrêté. » Il a aussi déclaré, à propos de l’échange d’état : « Je ne savais pas que l’état avait été échangé. » La commande s’est exécutée avec auto-approve vers 23 h, donc rien ne s’est arrêté pour demander une seconde fois.

Les deux récits présentent la proposition de l’agent différemment — l’entretien Rootly la formule ainsi : « c’est pénible de les supprimer un par un, et si je lançais simplement terraform destroy ? » — mais tous deux décrivent la même situation : la destruction proposée comme un rangement, et un opérateur qui croyait que seuls les doublons étaient concernés et l’a laissée s’exécuter. Le mécanisme de la défaillance n’est pas que l’agent ait mal compris la commande. C’est que l’agent raisonnait correctement à partir d’un fichier d’état qui décrivait la production, et que son opérateur n’avait aucun moyen de voir que le fichier avait changé.

HTML card headed 'The night of 26 to 27 February 2026, as Grigorev records it'. A vertical timeline lists: about 10:00 PM on Thursday 26 February, Terraform deploy begins without the state file, which was still on the old laptop; about 11:00 PM, a terraform command with auto-approve deletes the production infrastructure including the RDS database; about 12:00 AM, a support ticket is opened and the account is upgraded to AWS Business Support; about 12:30 AM, AWS support confirms a snapshot exists on their side; about 1 to 2 AM, a phone call is escalated to an internal AWS team; during Friday, backups, deletion protection and S3 state are put in place; about 10:00 PM on Friday 27 February, the database is restored and the platform is back online. A note at the foot reads 'Times are approximate and are the operator's own; all of them are local to him.'

Qu’est-ce qui a été détruit ?

Le fichier d’état à partir duquel l’agent travaillait désormais décrivait la production, de sorte que le destroy prévoyait la suppression de la production. Grigorev énumère ce qui a disparu :

• Le VPC qui contenait tout l’environnement.

• Le cluster ECS exécutant l'application.

• Les répartiteurs de charge en amont.

• L’hôte bastion utilisé pour accéder au réseau privé.

• La base de données Amazon RDS qui contient les données de la plateforme de cours.

• Les instantanés RDS automatisés qui étaient censés rendre tout ce qui précède récupérable.

Le dernier élément est celui qui a transformé une panne en une frayeur liée à la perte de données. Dans l’interview Rootly, l’explication de Grigorev est que la suppression d’une base de données managée sur AWS supprime également ses sauvegardes automatiques associées ; dans l’article, le support AWS lui a confirmé que sa base de données et tous ses instantanés avaient été supprimés et que « la requête API indiquait clairement à AWS de tout supprimer ». Quelle que soit la manière dont la suppression s’est propagée, l’effet à 23 h était celui qui comptait : la copie sur laquelle il comptait a été supprimée par la même opération que l’original.

HTML card headed 'What the destroy removed, and what it did not'. The left column, headed 'Deleted', lists the VPC, the ECS cluster, the load balancers, the bastion host, the Amazon RDS PostgreSQL database and the automated RDS snapshots. The right column, headed 'Not deleted', reads: no report of data being copied or exposed, this was deletion rather than disclosure; and the data itself, recovered from an AWS internal snapshot roughly 24 hours later. A strip below reads '2.5 years of submissions, homework, projects and leaderboard entries for every course run through the platform', and a highlighted line reads '1,943,200 rows in the courses_answer table when the restore was verified — one table, used as a completeness check, not a count of the whole database.'

La récupération en 24 heures

Le premier problème était que les sauvegardes semblaient avoir disparu, et le second était que l’une d’elles ne l’était pas. Grigorev savait qu’un instantané était pris chaque nuit à 2 h du matin. Dans la console RDS, il n’en trouva aucun, mais la liste des événements RDS indiquait toujours qu’une sauvegarde avait été créée ; en cliquant dessus, rien ne s’ouvrait. Il ne pouvait pas déterminer si l’instantané avait été supprimé ou s’il était simplement devenu invisible.

Il a ouvert un ticket de support vers minuit, puis a fait passer le compte au niveau AWS Business Support après avoir pris connaissance de l'engagement de réponse en une heure pour les incidents de production. La mise à niveau a ajouté environ 10 % à sa facture AWS, d'où le titre de son article. Le support a répondu en une quarantaine de minutes, a confirmé la suppression et lui a indiqué qu'un instantané existait du côté d'AWS qu'il ne pouvait pas voir dans sa console. Un appel de 40 à 60 minutes a suivi et a été escaladé vers une équipe interne. Exactement 24 heures après la suppression de la base de données, AWS a restauré l'instantané et celui-ci est apparu dans sa console ; il a reconstruit l'instance à partir de celui-ci via Terraform. Pendant l'attente, il avait reconstruit l'infrastructure environnante et consolidé plusieurs répartiteurs de charge en un seul.

La base de données restaurée contenait 1 943 200 lignes dans la courses_answer table, ce qu'il cite comme la vérification que la restauration était complète. Ce chiffre est souvent repris comme la taille de la perte. Il s'agit du nombre de lignes d'une seule table, utilisé comme preuve que les données sont revenues — et non d'un total pour la base de données, ni d'un décompte des étudiants concernés, qu'aucune des sources ne fournit.

L’avertissement qui n’en était pas un

Plusieurs récits comportent une formule selon laquelle Claude avait prévenu Grigorev au préalable et que son avertissement avait été ignoré. Ce que les sources permettent d’affirmer est plus limité, et cette différence change ce dont ce cas est un exemple. L’agent a bien plaidé contre la configuration Terraform partagée avant toute destruction, et cet avis a été rejeté. Aucun des deux récits de Grigorev ne décrit l’agent avertissant que le destroy atteindrait la production. Il dit qu’il ne savait pas que le fichier d’état avait été remplacé, et dans les deux récits, la proposition de l’agent est présentée comme une remise en ordre plutôt que comme un risque signalé et écarté. L’avertissement ignoré portait sur l’architecture, plus tôt dans la migration, et non sur la commande.

Cette distinction sépare deux défaillances différentes. Un agent qui voit le danger et est désavoué constitue une histoire de gouvernance portant sur une décision humaine. Un agent qui ignore l’existence du danger, parce que le fichier décrivant le monde a changé sous ses pieds, constitue une histoire d’outillage portant sur l’état, les autorisations et les points de validation. Le récit de Grigorev est le second, et la classification propre à l’archive le reflète : l’enregistrement porte l’étiquette ROGUE de l’archive pour une action d’agent qui s’est écartée de l’intention de son opérateur, et l’entrée de l’AI Incident Database qui se trouve en dessous classe l’intention comme non intentionnelle, selon la taxonomie MIT 7.3, manque de capacité ou de robustesse, dans le domaine de risque de la sécurité, des défaillances et des limites des systèmes d’IA, au stade post-déploiement. La base de données fait précéder sa liste d’entités de « alleged », sa formulation standard pour un cas auto-déclaré qu’aucune autorité n’a tranché.

Où le blâme est retombé

Grigorev ne le distribue pas. « Cet incident était de ma faute », écrit-il, en énumérant trois causes : il avait considéré plan, apply et destroy comme délégables ; il faisait confiance à des sauvegardes qu’il n’avait jamais testées par restauration ; et la base de données était trop facile à supprimer. Il note qu’en attendant AWS, il devait envisager que les données aient pu disparaître définitivement — pour le cours Data Engineering, qui en était alors à ses derniers modules, il planifiait déjà une récupération, et pour les cours plus anciens, une restauration échouée aurait sonné leur fin.

L’évaluation de Tom's Hardware, publiée le lendemain de son article, est identique sur le fond : « les erreurs peuvent être attribuées à une supervision inappropriée ». Sa critique va plus loin que la sienne, en pointant des identifiants de portée étendue accordés à l’agent et des autorisations qui n’ont jamais été restreintes pour un environnement de production. Aucun régulateur, organisme de normalisation ou fournisseur n’a pris position. Il n’y a ici ni CVE, ni divulgation de vulnérabilité, ni jailbreak de modèle : l’agent n’a pas été trompé, il a fait l’objet d’une confiance excessive.

Qu’est-ce qui a changé par la suite ?

Grigorev a mis en œuvre les mesures de protection alors qu’AWS travaillait encore à la restauration, et les a publiées sous forme de liste. Selon ses propres termes et dans son ordre :

• Sauvegardes que Terraform ne gère pas, ainsi que des copies basées sur S3 stockées séparément de la base de données et de l'état de l'infrastructure.

• Un test de restauration nocturne : la sauvegarde automatisée de 2 h est utilisée vers 3 h pour créer une nouvelle instance de base de données, ce qui prend 20 à 30 minutes, puis une fonction Lambda orchestrée par Step Functions vérifie qu’elle est utilisable au moyen d’une simple requête de lecture avant que l’instance soit arrêtée plutôt que supprimée. La copie de la veille est supprimée, de sorte qu’une réplique récente reste toujours disponible.

• Protection contre la suppression à deux niveaux : dans la configuration Terraform et dans AWS lui-même. Il note que ces protections peuvent toujours être supprimées par quiconque les désactive explicitement, mais qu’elles ajoutent des frictions.

• La gestion des versions sur les sauvegardes S3, de sorte qu'une suppression conserve les versions antérieures et que {{1}}vider un bucket{{/1}} nécessite d'abord d'en supprimer le contenu.

• L'état Terraform a été déplacé vers S3, ce qui supprime la condition qui en était à l'origine — un fichier d'état qui n'existait que sur un seul ordinateur portable et disparaissait lorsqu'il changeait de machine.

• L’agent n’exécute plus du tout Terraform. « Toutes les autorisations sont désactivées. Aucune exécution automatique. Aucune écriture de fichier », écrit-il. Le flux de travail consiste désormais à générer un plan, à le passer en revue manuellement et à exécuter lui-même les commandes. Le nouveau projet a également sa propre configuration Terraform distincte.

Toutes les recommandations n’ont pas été suivies. Dans l’interview Rootly, il dit avoir conservé un seul compte AWS, jugeant que des comptes de développement et de production séparés et un pipeline d’approbation comme Atlantis dépassaient les besoins d’une personne seule. C’est la forme honnête de l’après-coup : les correctifs sont réels, et ce sont des correctifs qu’une personne seule peut maintenir.

Ce que cet enregistrement est, et ce qu’il n’est pas

Il s'agit d'un incident opérationnel documenté et auto-déclaré, avec un préjudice financier et de disponibilité réel, et il est exceptionnellement lisible parce que la personne à qui il est arrivé a consigné toute la séquence, y compris les parties qui relevaient de sa propre erreur. Ce n'est pas la preuve qu'un modèle a poursuivi un objectif qui lui était propre, et l'étiquette ROGUE de l'archive doit être comprise comme décrivant la divergence entre l'action de l'agent et l'intention de son opérateur, plutôt que quelque intention que ce soit de la part de l'agent.

Le détail à retenir est celui qui a sauvé les données. Les sauvegardes personnelles de Grigorev ont été supprimées avec la base de données qu’elles protégeaient, et son instantané nocturne lui était invisible, alors même que le journal des événements affirmait qu’il existait. Ce qui a permis de restaurer 2,5 ans de travaux de cours, c’est une copie détenue du côté d’AWS dont il n’avait jamais eu connaissance et qu’il n’aurait pas pu tester. Une sauvegarde à partir de laquelle vous n’avez jamais restauré est une croyance, pas un contrôle — et dans ce cas, la croyance s’est trouvée vraie uniquement parce que quelqu’un d’autre en conservait une seconde.

Abstract closing artwork on a dark navy field: on the left, a wide rectangle of infrastructure tiles sits collapsed into broken segments and scattered fragments; on the right, outside the boundary of that rectangle, a single small tile glows intact on its own, connected to nothing. Thin amber lines from the wreckage reach toward it but stop short. No text, no people and no organisation logos appear. The OrcaRouter logo is composited in the bottom-right corner.