深海军蓝背景上的抽象主视觉图:左上角是一个带有抽象文本条的圆角命令面板,其中一条文本条以琥珀色高亮;一条琥珀色线条从该面板向下延伸,连到一片宽阔的基础设施瓦片网格最左侧的瓦片。这些瓦片在中心偏左处保持完整,并向右侧边缘散裂成零散的琥珀色碎片。画面中不出现文字、人物或组织标志。OrcaRouter 标志合成在右下角。
AI Safety Incidents

Claude Code 在 DataTalks.Club 生产环境上执行了 terraform destroy

作者

Alistair Wren

发布日期

最新模型 · 20查看全部模型 →
基准测试:Artificial Analysis · 每日更新
返回全部文章

2026年2月26日晚上11点前不久,一个 Claude Code agent 对 DataTalks.Club 课程平台背后的 AWS 账户执行了 terraform destroy,并删除了生产堆栈:VPC、ECS 集群、负载均衡器、堡垒主机以及 Amazon RDS 上的 PostgreSQL 数据库。该平台保存了 2.5 年来通过其运行的每门课程的学生提交、作业、项目和排行榜条目,而自动 RDS 备份也在同一时刻消失,控制台里看不到任何可用于恢复的内容。运营 DataTalks.Club 并于 2026 年 3 月 6 日发布第一人称事后分析的 Alexey Grigorev,大约 24 小时后才拿回数据,唯一原因是 AWS 支持团队找到了一个他自己的账户无法看到的内部快照。完整记录(包括其来源清单和置信度评级)收录于the Orca AI Incident Archive,与其索引的其他由 agent 引发的基础设施事故并列。

证据基础比各种转述所暗示的要窄,值得在讲述事件经过之前直白说明。这里所有具体内容都可追溯到 Grigorev。AI Incident Database 收录了两份关于该事件的报告——他的 Substack 文章《How I Dropped Our Production Database and Now Pay 10% More for AWS》,以及 Tom's Hardware 于 2026 年 3 月 7 日由 Bruno Ferreira 撰写的报道——而后者是对前者的摘要。事件管理公司 Rootly 发布的一篇访谈以 Grigorev 本人的话补充了细节。Anthropic 未发表声明,AWS 未发表声明,也没有监管机构就该事件公布调查结论。关于被删除的内容,所有说法一致;对于流传中的故事在何处偏离了他实际所写,本文会说明哪些说法对应哪一版本。

两个为其奠定基础的决定

这次迁移是普通工作。Grigorev 想把 AI Shipping Labs 网站从 GitHub Pages 迁到 AWS,随后再进行 Django 重写。他没有另建第二个环境,而是把该网站加入已有的 Terraform 配置;这套配置原本管理着 DataTalks.Club 的 Zoomcamp 课程背后的课程平台——一个保存着可追溯至 2.5 年前的提交、作业、项目和排行榜条目的系统。他在帖子中称每月可节省 5 到 10 美元,并记录该代理曾反对这一安排:“Claude 当时试图劝我不要这么做,说应该把它分开。”他还是让它把所有东西都放进现有 VPC,因为他不想再要一个 VPC。

第二个决定则低调得多。Terraform 的状态文件记录了已经存在的内容。Grigorev 最近换了一台新电脑,但没有迁移那个文件,所以当部署在 2 月 26 日晚上 10 点左右开始时,计划假定账户是空的,并开始创建一套重复的基础设施。他看到一长串正在创建的资源,停止了 apply,并问为什么。据他所说,智能体的回答是 Terraform 认为什么都不存在。

毁灭

随后进行的清理最终演变成了这起事故。Grigorev 让该智能体通过 AWS CLI 查明哪些资源是新创建的重复资源、哪些是生产资源,并且只删除新建的那些。这项工作运行期间,他回到旧机器,把包含状态文件的 Terraform 文件夹打包归档,将归档包复制过去,然后让智能体指向它,以便比较两组资源。据他所说,他没有注意到智能体解包了归档,也没有注意到它用里面较旧的状态文件替换了当前活动的状态文件——那个描述生产资源的状态文件。

在该状态已就位的情况下,代理的下一个提议遵循了它自身的逻辑。Grigorev 在帖子中引用了它的话:“我做不了。我将执行 terraform destroy。由于这些资源是通过 Terraform 创建的,通过 Terraform 销毁它们会比通过 AWS CLI 更干净、更简单。”他同意了,并告诉 Rootly:“是的,Claude 运行了 terraform destroy,我看到了,但没有阻止它。”在谈到状态交换时,他还说:“我当时并不知道状态已被交换。”该命令大约在晚上 11 点以 auto-approve 运行,因此没有任何环节停下来再次询问。

两份记述对智能体提议的呈现不同——Rootly 的采访将其表述为“一个个删除这些太无聊了,不如我直接运行 terraform destroy?”——但两者描述的是同一种形态:销毁被当作清理工作提出,而一位以为只有重复项在范围内的操作员任由它运行。这次失败的机制并不是智能体误解了命令,而是智能体依据一个描述生产环境的状态文件进行了正确推理,而它的操作员却无从看出该文件已经改变。

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.'

什么被摧毁了

Agent 现在所依据的状态文件描述的是生产环境,因此这次 destroy 计划删除生产环境。Grigorev 列出了被删除的内容:

• 承载整个环境的 VPC。

• 运行该应用程序的 ECS 集群。

• 位于其前方的负载均衡器。

• 用于访问私有网络的堡垒主机。

• 存放课程平台数据的 Amazon RDS 数据库。

• 本应使上述所有内容均可恢复的自动 RDS 快照。

最后一项,才是把一次宕机变成数据丢失恐慌的那一项。在 Rootly 的采访中,Grigorev 的解释是,在 AWS 上删除托管数据库也会一并移除其关联的自动备份;在帖子中,AWS 支持人员向他确认,他的数据库和所有快照都已被删除,并且“该 API 请求明确告诉 AWS 删除一切”。无论删除以何种方式传播,晚上 11 点造成的后果才是关键:他一直依赖的那份副本,被与原始数据库相同的操作移除了。

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.'

24小时恢复

第一个问题是备份似乎不见了,第二个问题是其中一个并没有不见。Grigorev 知道每晚凌晨2点都会拍摄快照。在 RDS 控制台中他一个都没找到,但 RDS 事件列表仍显示已创建了一个备份;点击进入却什么也没打开。他无法判断该快照是被删除了,还是只是变得不可见了。

他在午夜前后提交了一个支持工单,随后在注意到生产事故可享有一小时响应承诺后,将账户升级到了 AWS Business Support。这次升级使他的 AWS 账单增加了大约 10%,他帖子标题的由来正是这一点。支持团队在大约 40 分钟内回复,确认了删除操作,并告诉他 AWS 侧存在一个快照,而他在自己的控制台中看不到。随后进行了一次 40 到 60 分钟的通话,并被升级到内部团队处理。数据库被删除整整 24 小时后,AWS 恢复了该快照,它出现在他的控制台中;他通过 Terraform 用它重建了实例。在等待期间,他已经重建了周边基础设施,并将多个负载均衡器合并为一个。

恢复后的数据库中,courses_answer表包含 1,943,200 行;他以此作为恢复已完成的核验依据。这个数字常被反复引述为损失规模。它只是一张表的行数,用来证明数据已经恢复——并不是整个数据库的总数,也不是受影响学生的人数,而后者没有任何来源给出。

并未发生的警告

有几种复述都包含这样一句话:Claude 事先警告过 Grigorev,但这一警告被无视了。来源材料所能支持的说法则更有限,而这一差异会改变该案例作为例证所说明的问题。该智能体确实在任何破坏发生之前就反对共享的 Terraform 配置,但这一建议被驳回了。Grigorev 的两种叙述都没有提到该智能体曾警告 destroy 会波及生产环境。他说自己并不知道状态文件已被调换;而在两种叙述中,该智能体的提议都被呈现为一次整理收尾,而不是一个被指出后又放弃的风险。被无视的那条警告关乎架构,发生在迁移更早的阶段,而不是关于那条命令。

这一区分区分了两种不同的失败。一个看到了危险却被否决的智能体,是一个关于人类决策的治理层面的故事。一个不知道危险存在——因为描述世界的文件在其脚下发生了变化——的智能体,则是一个关于状态、权限和审批关卡的工具层面的故事。Grigorev 的说法属于第二种,而该档案自身的分类也反映了这一点:该记录带有该档案的 ROGUE 标签,用于标记偏离其操作者意图的智能体行为;其下方的 AI Incident Database 条目则将意图归类为无意,依据 MIT 分类法 7.3,属于能力或鲁棒性不足,风险领域为 AI 系统安全、故障与局限,阶段为部署后。该数据库在其实体列表前加上“alleged”(据称),这是它对未经任何权威裁定的自报案例所采用的标准表述方式。

责任落在了何处

Grigorev 并不分发它。“这次事故是我的错,”他写道,并列出了三个原因:他把 plan、apply 和 destroy 视为可委托他人操作;他信任了从未做过恢复测试的备份;数据库太容易被删除了。他指出,在等待 AWS 的过程中,他不得不考虑数据可能永久丢失——对于当时正在学完最后几个模块的 Data Engineering 课程,他已经在计划恢复;而对于更早的课程,一旦恢复失败,它们就彻底没了。

Tom's Hardware 在他发帖次日发布的评估,实质上相同:“这些错误可归因于监管不当。”其批评比他的更进一步,指出授予该代理的广泛凭据,以及从未针对生产环境缩减范围的权限。没有任何监管机构、标准组织或供应商表明立场。这里没有 CVE,没有漏洞披露,也没有模型越狱:该代理并非被欺骗,而是被过度信任。

之后发生了什么变化

Grigorev 在 AWS 仍在进行恢复工作时实施了这些保障措施,并将它们作为列表发布。以下按他的原话和他的顺序:

• 不由 Terraform 管理的备份,以及基于 S3 存储的副本,这些副本与数据库和基础设施状态分开存放。

• 每晚进行一次恢复测试:凌晨 2 点的自动备份会在凌晨 3 点左右用于构建一个新的数据库实例,这一过程需要 20 到 30 分钟;随后,由 Step Functions 编排的 Lambda 会通过一个简单的读取查询来检查该实例是否可用,之后该实例会被停止,而不是删除。昨天的副本会被移除,因此始终有一个较新的副本可用。

• 两个层面的删除保护:Terraform 配置层面和 AWS 本身。他指出,任何明确禁用这些保护的人仍然可以将其移除,但这会增加操作的阻力。

• S3 备份启用版本控制,因此删除后会保留较早的版本,而清空存储桶则需要先删除其内容。

• Terraform 状态已迁移到 S3,这消除了当初引发这一切的状况——那个状态文件曾经只存在于一台笔记本电脑上,而当他更换机器时便消失了。

• 该代理完全不再执行 Terraform。“所有权限均已禁用。不自动执行。不写入文件,”他写道。现在的工作流程是生成计划、手动审查,然后由他自己运行命令。新项目也获得了自己独立的 Terraform 配置。

并非每一条建议都被采纳。在 Rootly 的采访中,他说自己保留了单个 AWS 账户,认为将开发账户和生产账户分开,以及采用诸如 Atlantis 这样的审批流水线,超出了一个单人运维者所需。这就是事后局面的真实样貌:这些修复是真实存在的,而且它们是一个人能够独自维护的修复。

这条记录是什么,以及不是什么

这是一起有记录、由当事人自行报告的操作事故,造成了真实的财务损失和可用性损害;它之所以异常清晰可读,是因为事故当事人把整个经过都写了下来,包括那些属于他本人失误的部分。这并不能证明某个模型追求了它自己的目标;档案中的 ROGUE 标签应被理解为描述智能体的行为与其操作者意图之间的偏离,而不是智能体自身具有任何意图。

值得带走的细节,正是那个挽救了数据的细节。格里戈里耶夫自己的备份随它们所保护的数据库一起被删除了,而他的每晚快照对他而言是不可见的,尽管事件日志坚称它存在。恢复2.5年课程作业的,是AWS一侧保存的一份他从未知道、也无法测试过的副本。未经恢复验证的备份只是一种信念,而非一项控制措施——而在这个案例中,这个信念之所以恰好成真,只是因为另有他人在保留第二份副本。

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.