問題
AI 程式代理(coding agent)好用,是因為它能執行指令、編輯檔案、提交程式碼。同樣的能力也讓一次無心之過代價高昂:代理可能為了讓建置變綠而弱化測試、把機密提交進版本庫,或在錯的目錄下執行刪除。光靠 prompt 裡的指示無法可靠防止這些事:模型會忘記,長對話被壓縮時指示也可能遺失。我們要的是保留速度,同時擋掉最糟的錯誤。
做法
- 把規則放在每次呼叫工具都會執行的程式碼裡,而不是寫在指示文字中。
- 疊加相互獨立的防護層,讓單一缺口不致致命。
- 每個代理只給任務所需的最小權限。
- 把每次事故當成新關卡的來源;檢討時問的是「系統讓什麼成為可能」,而不是「誰出錯」。
運作方式
- 驗證與完整性。 hook 在每次 commit 與 push 前執行專案自己的 verify 腳本,失敗就擋下提交。另一道檢查會標出被刪除的測試、新增的 skip 標記、被移除的斷言(assertion)與被改掉的預期值;代理必須還原或說明理由。代理不能修改 verify 腳本,gitleaks 掃描則會擋下含機密的 commit。
- 多模型審查。 非瑣碎的工作,先由一個模型寫計畫,並在任何程式碼出現前寫好可執行的驗收檢查。另一家廠商的模型以唯讀方式對照真實程式碼審查計畫,規劃者逐項裁決每個 finding。子代理依鎖定的檢查實作,外部模型審查 diff;最高難度級別再加變異測試(mutation check),找出「程式壞了測試仍會通過」的測試。一份政策檔決定哪些專案可以送給哪家廠商。
- 允許清單式 MCP 伺服器。 launchpad 伺服器只提供寫在受審設定檔裡的 DevOps 動作。指令是不經 shell 的參數陣列,參數會驗證,子行程只拿到清理過的環境變數,輸出經過遮蔽,每次呼叫(包含被拒絕的)都寫入稽核紀錄。唯一會改動正式環境的動作需要確認。
成果
2026-10-12,一個擁有完整 shell 的子代理執行暫存目錄實驗,結果刪光了我們的 projects 資料夾:32 個頂層項目、約 199 GB,歷時約兩分鐘。一連串小事湊在一起:zsh 不會拆開未加引號的變數,所以 git 那幾行全部失敗;set -e 在工具的包裝層裡沒有作用;互動式 shell 的 cd alias 跳進了真正的專案;接著相對路徑的 find ... -exec rm -rf 在上一層執行。指令超過 timeout 後仍在背景繼續跑。
線上網站、程式庫與雲端帳號都沒有受影響。資料從一份 20 小時前的 APFS 本機快照救回,刪除後約 3.5 小時完成。一份涵蓋 19 個資源的基礎設施 state 檔遺失,約六小時未 commit 的規劃文件也只救回一部分。
當時沒有任何東西擋得住:沒有 hook 檢查破壞性指令、沙盒是關的、只需讀檔和寫一個檔的任務卻拿到完整 shell,唯一的防護是一句「用暫存目錄」。
當天核准了八道關卡,包括:PreToolUse 守衛 hook,擋下遞迴刪除,除非每個目標都是位於目前專案或暫存目錄內的明確路徑(22 個測試,其中一個用的就是事故當時的指令);cd alias 只在互動式 shell 設定;開啟沙盒;只做審查或寫文件的子代理不給 shell;以及以「先停下所有代理」開頭的事故處理手冊。
學到的事
- hook 是安全帶,不是邊界。守衛只看行內指令,我們接受部分已知缺口,因為沙盒才是最後防線。要把這點講清楚,並用傷過你的那條指令來測試守衛。
- 權限配合任務。只審查或寫文件的子代理不需要 shell。
- 事先規劃復原。調查前先停下所有代理,把 git 不管的資料另存一處,並及早 commit。