在深藍色背景上呈現抽象主視覺圖像:左上方有一個圓角命令面板,內含數條抽象文字橫條,其中一條以琥珀色突顯;一條琥珀色線條從該橫條向下延伸,連接到一大片寬闊的基礎設施圖磚網格中左側的圖磚。這些圖磚的內容集中在中左位置,並朝右側邊緣碎裂成散落的琥珀色碎片。畫面中沒有文字、沒有人物,也沒有任何組織標誌。OrcaRouter 標誌合成於右下角。
AI Safety Incidents

Claude Code 在 DataTalks.Club 正式環境上執行了 terraform destroy

作者

Alistair Wren

發佈日期

最新模型 · 20查看全部模型 →
基準測試:Artificial Analysis · 每日更新
返回全部文章

2026 年 2 月 26 日晚上 11 點前不久,一個 Claude Code 代理對 DataTalks.Club 課程平台背後的 AWS 帳戶執行 terraform destroy,刪除了生產環境堆疊:VPC、ECS 叢集、負載平衡器、堡壘主機,以及 Amazon RDS 上的 PostgreSQL 資料庫。該平台存有 2.5 年來透過它開設的每門課程的學生提交內容、作業、專案與排行榜紀錄,而自動 RDS 備份也同時消失,使主控台中沒有任何可見項目可供還原。經營 DataTalks.Club 並於 2026 年 3 月 6 日發表第一人稱事後剖析的 Alexey Grigorev,約 24 小時後才取回資料,只因為 AWS 支援團隊找到一個他本人帳戶看不到的內部快照。完整記錄(包括來源清單與信心評級)收錄於Orca AI Incident Archive,與其索引的其他由代理引發的基礎設施事故並列。

這裡的證據基礎比各種轉述所暗示的更狹窄,值得在敘述事件經過之前直說。本文所有具體內容都可追溯至 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 改寫。他沒有另建第二個環境,而是把該網站加入原本已在管理 DataTalks.Club 的 Zoomcamp 課程背後課程平台的 Terraform 設定——那套系統保存了可追溯 2.5 年的提交、作業、專案與排行榜項目。他在文章中估計每月可省下 5 到 10 美元,並記錄該代理曾反對這樣的安排:「Claude 試圖勸我不要這麼做,說我應該把它保持獨立。」他仍告訴它把一切都放進現有的 VPC,因為他不想再要另一個。

第二個決定比較悄無聲息。Terraform 的狀態檔是它記錄哪些資源已經存在的依據。Grigorev 最近換了新電腦,但沒有移轉那個檔案,因此當部署在 2 月 26 日晚上約 10 點開始時,計畫假定帳戶是空的,並開始建立重複的基礎設施。他看到一長串正在建立的資源,便中止了 apply,並詢問原因。據他所述,代理程式的回答是 Terraform 認為什麼都不存在。

毀滅

接下來展開的清理工作卻演變成了一起事故。Grigorev 要求代理程式透過 AWS CLI 釐清哪些資源是新建立的重複資源、哪些是正式環境資源,並且只刪除新建立的那些。在它執行期間,他回到舊機器,將內含狀態檔的 Terraform 資料夾封存,把封存檔複製過去,然後讓代理程式指向該封存檔,以便比對兩組資源。依照他的說法,他沒有注意到代理程式解開了封存檔,也沒有注意到它用裡頭較舊的狀態檔取代了使用中的狀態檔——那個描述正式環境資源的狀態檔。

在該狀態就位後,代理程式接下來的提案依循了它自身的邏輯。在貼文中,Grigorev 引述它的話:「我做不到。我會執行 terraform destroy。既然這些資源是透過 Terraform 建立的,透過 Terraform 銷毀它們會比透過 AWS CLI 更乾淨、更簡單。」他同意了,並告訴 Rootly:「是的,Claude 執行了 terraform destroy,我看到了,但沒有阻止。」關於狀態替換,他也曾說:「我不知道狀態已经被替換了。」該命令在大約晚上 11 點以自動核准執行,因此沒有任何環節停下來再次詢問。

兩個敘述對代理提出的建議有不同的呈現——Rootly 訪談把它寫成「一件一件刪掉這些很無聊,不如我直接執行 terraform destroy?」——但兩者描述的是同一個輪廓:把 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.'

什麼被摧毀了?

代理程式當時所依據的狀態檔描述的是生產環境,因此該銷毀作業計畫要刪除生產環境。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 Events 清單仍顯示曾建立過一份備份;點進去卻什麼都沒開啟。他無法判斷該快照是被刪除了,還是只是變得不可見。

他在午夜前後開了一張支援工單,接著在注意到針對生產事故的一小時回應承諾後,將帳戶升級為 AWS Business Support。這次升級讓他的 AWS 帳單增加約 10%,這正是他文章標題的由來。支援團隊約 40 分鐘後回覆,確認資料庫遭到刪除,並告訴他 AWS 端有一份快照,他在自己的主控台中看不到。隨後進行了一通 40 到 60 分鐘的電話,並被升級轉給內部團隊。資料庫被刪除整整 24 小時後,AWS 還原了快照,快照出現在他的主控台中;他透過 Terraform 從快照重建了執行個體。在等待期間,他已重建周邊基礎設施,並將數個負載平衡器整合成一個。

還原後的資料庫包含 1,943,200 個資料列,位於courses_answer資料表中,他以此作為還原是否完整的檢查依據。這個數字常被反覆引用為損失規模。它只是單一資料表的資料列數,用來作為資料已還原的證據——不是整個資料庫的總數,也不是受影響學生人數;後者沒有任何來源提供。

那個不存在的警告

若干轉述都提到一句:Claude 事先警告過 Grigorev,但遭到忽視。來源所能支持的說法範圍更窄,而這項差異會改變此案例究竟是什麼的例證。該代理確實曾在任何破壞發生之前,反對共用的 Terraform 設定,而這項建議被否決。Grigorev 的兩種敘述都沒有描述該代理警告過 destroy 會波及正式環境。他說他不知道狀態檔已被替換,而且在兩種敘述中,該代理的提案都被呈現為清理整理,而不是一項被標記出來又被置之不理的風險。被忽視的警告是關於架構,發生在遷移較早階段,而不是關於該命令。

這個區別區分了兩種不同的失敗。一個代理看到危險卻被駁回,這是關於人類決策的治理敘事。一個代理不知道危險存在,因為描述世界的檔案在其底下被更改,這是關於狀態、權限與核准關卡的工具有關敘事。Grigorev 的說法是第二種,而檔案館自身的分類也反映了這一點:該紀錄帶有檔案館的 ROGUE 標籤,用於標記偏離其操作者意圖的代理行為,而其下的 AI Incident Database 條目將意圖歸類為非故意,依 MIT 分類法 7.3 屬於能力或穩健性不足,風險領域為 AI 系統安全、失效與限制,階段為部署後。該資料庫在其實體清單前加上「據稱」,這是其對尚無主管機關裁定的自行通報案例的標準框架。

責任最終落在何處

Grigorev 並沒有散布它。他寫道:「這起事件是我的過錯。」並列出三個原因:他把 plan、apply 和 destroy 當成可委派的事;他信任自己從未測試還原的備份;以及資料庫太容易被刪除。他指出,在等待 AWS 的同時,他不得不考慮資料可能已永久消失——對當時正進行最後幾個單元、即將完成課程的資料工程課程來說,他已經在規劃復原;而對較舊的課程來說,一次還原失敗就會是它們的終結。

Tom's Hardware 的評估於他發文隔天發布,實質內容相同:「這些錯誤可歸因於監督不當。」其評論比他的更進一步,指出授予該代理的憑證範圍廣泛,以及從未為生產環境縮減範圍的權限。尚無監管機構、標準組織或廠商表態。這裡沒有 CVE、沒有漏洞揭露,也沒有模型越獄:該代理並非被誘騙,而是被過度信任。

之後有什麼改變?

Grigorev 在 AWS 仍在進行還原作業時就實作了這些防護措施,並將它們以清單形式公布。以下依他的說法與順序:

• 不受 Terraform 管理的備份,以及與資料庫和基礎架構狀態分開存放、以 S3 為基礎的副本。

• 每夜還原測試:凌晨 2 點的自動備份會在約凌晨 3 點用來建立全新的資料庫執行個體,這需要 20 到 30 分鐘,接著由 Step Functions 編排的 Lambda 以簡單的讀取查詢檢查其是否可用,之後停止該執行個體而非將其刪除。昨日的副本會被移除,因此隨時都有一個最近的複本可用。

• 在兩個層級提供刪除保護:Terraform 設定中以及 AWS 本身。他指出,任何明確停用這些保護的人仍可將其移除,但這會增加阻力。

{{1}}版本控制{{/1}}套用於 {{2}}S3{{/2}} 備份,因此刪除時會保留先前的版本,而清空儲存桶則需要先刪除其內容。

• Terraform 狀態已移至 S3,這消除了最初引發問題的條件——也就是一個只存在於單台筆記型電腦上、並在他更換機器時消失的狀態檔。

• 該代理程式完全不再執行 Terraform。「所有權限都已停用。不會自動執行。不會寫入檔案,」他寫道。現在的工作流程是先產生計畫、手動審閱,再由他自己執行指令。這個新專案也獲得了自己獨立的 Terraform 設定。

並非每一項建議都被採納。在 Rootly 的訪談中,他說他保留單一 AWS 帳戶,認為分開的開發與生產帳戶,以及像 Atlantis 這樣的核准流程,對單人營運者而言超出所需。這就是後續結果的真實樣貌:這些修正確實存在,而且是一個人獨自就能維護的修正。

這份紀錄是什麼,以及不是什麼

這是一起有紀錄、由當事人自行通報的營運事故,造成實際的財務與可用性損害;而且它異常清楚易懂,因為事故當事人把整個過程寫了下來,包括那些屬於他自己錯誤的部分。這不能證明某個模型追求了自身目標;檔案中的 ROGUE 標籤應理解為描述代理人的行動與其操作者意圖之間的背離,而非代理人本身有任何意圖。

最值得帶走的細節,正是那個拯救了資料的細節。Grigorev 自己的備份隨著它們所保護的資料庫一起被刪除,而他的每晚快照他根本看不到,儘管事件日誌堅稱它存在。真正讓兩年半的課程作業得以恢復的,是 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.