MapleCheng

在浩瀚的網路世界中無限潛水欸少年郎!

0%

當 AI 會照文件下指令,文件就成了軟體供應鏈

以前我們閱讀技術文件,是為了理解系統,再由工程師判斷哪些指令值得執行。現在 Coding Agent 可以自己搜尋文件、讀取 README 或 llms.txt,接著安裝套件、執行腳本、修改設定。表面上只是把操作速度加快,實際上卻悄悄改變了一條重要邊界:文件已經從參考資料,變成可能驅動執行環境的控制輸入。

這也是我認為 AI Coding 安全最容易被低估的地方。危險不一定藏在程式碼裡,有時只是藏在一段看起來很合理的安裝說明中。

人會停下來懷疑,Agent 可能只看到下一步

一般工程師看到陌生指令時,多少會做一些直覺檢查:套件名稱是否正確、網域是不是官方的、指令為什麼需要系統權限、下載後究竟執行了什麼。這些判斷未必完整,但人知道自己正在跨過「閱讀」與「執行」的界線。

Agent 的工作流不同。它收到的目標通常是「把專案跑起來」或「修好建置錯誤」,於是文件中的安裝步驟很容易被理解為完成任務所需的下一個動作。若文件寫著安裝某個尚未註冊的套件、連到一個沒有人維護的網域,或下載腳本後直接交給 shell,模型可能只把它視為一串彼此合理的步驟。

問題不在 Agent 不夠聰明,而在我們把兩種不同信任等級的能力接得太順:前一步讀取外部資料,下一步就在具有憑證、原始碼與網路權限的環境執行。

文件格式不會自動帶來可信度

README.md、套件文件、論壇回答、搜尋摘要或 llms.txt,都只是內容載體。它們方便模型理解,卻不代表內容經過驗證。即使檔案位於官方網站,也可能過期、遭到供應鏈污染,或引用已經轉手的套件與網域。

因此,我不會把「模型讀得懂」等同於「系統可以照做」。真正需要驗證的是指令背後的實體:

  • 套件是否存在於預期的 registry,發布者與維護狀態是否合理;
  • 網域是否屬於已知組織,憑證與重新導向是否符合預期;
  • 版本是否被明確鎖定,雜湊或簽章能否核對;
  • 腳本會讀寫哪些路徑、使用哪些秘密、連到哪些外部服務;
  • 執行結果能否在隔離環境重現,而不是只在某台開發機「剛好成功」。

這些檢查不能只靠模型在腦中多想一下。它們應該成為工具層與執行平台的政策。

把「資料到 shell」設計成明確的閘門

我會把 Coding Agent 的流程拆成至少三個階段:發現、驗證、執行。

發現階段可以自由讀取文件與搜尋候選做法,但不取得正式憑證,也不能直接修改重要環境。驗證階段負責解析套件、網域、版本、下載內容與預期副作用,產生一份機器可讀的執行計畫。到了執行階段,平台只允許已驗證的 artifact 與參數進入 sandbox,並記錄實際下載雜湊、網路目的地、檔案變更及程序結果。

這樣做的重點,不是每一行指令都要求人按一次同意。若審批畫面永遠只顯示一長串 shell,最後一定會退化成反射式按鈕。更實用的方式,是依風險分級:

  • 已鎖版、來源可信且只作用於隔離環境的依賴,可以自動執行;
  • 新增 registry、首次出現的網域或未鎖定版本,需要提高檢查強度;
  • pipe-to-shell、提升權限、讀取秘密或寫入專案外路徑,預設拒絕或要求明確核准;
  • 文件內容與真正執行的 canonical command 必須一致,不能讓預覽與執行各用一套字串。

此外,網路權限也不該一路開到底。讀文件的 Agent 可以連外,不代表執行 build 的程序也能任意連外;需要抓依賴時,可以只允許核准的 registry 與 artifact host。把能力拆開,攻擊者即使控制其中一段內容,也不容易完成整條利用鏈。

真正要保存的是證據,不只是對話

發生異常時,只保存 Agent 的自然語言回答幫助有限。技術團隊需要知道它讀了哪份文件、解析出哪個依賴、為何信任該來源、實際執行什麼、下載內容的雜湊為何,以及最後改了哪些檔案。

這些資料應該進入 execution trace,並能被用來建立回歸測試。例如刻意放入相似套件名稱、失效網域、重新導向與惡意安裝片段,確認 Agent 是否會停在驗證閘門,而不是一路追求「任務完成」。安全測試的目標不該只是模型有沒有拒絕,而是平台是否真的阻止未驗證內容跨進執行層。

自動化越順,邊界越要刻意留下來

AI Coding 帶來的價值,正是把「查資料、理解、操作」串成連續流程。但也因為流程太順,人原本會停下來確認的地方,很容易一起被消掉。

站在技術主管的角度,我不想用全面禁止 shell 來解決問題,那會讓 Agent 失去大半價值。我更在意的是:哪些資料可以影響決策、哪些決策可以變成指令,以及指令跨進真實環境前,有沒有經過可驗證、可稽核、可回復的閘門。

當 AI 開始照著文件工作,文件就已經是供應鏈的一部分。這時候,我們治理的不只是程式碼來源,而是每一段可能把外部文字轉成內部動作的路徑。