AIS3 2026「當代理者被授予工具」課程筆記

上一堂課談的是模型為何回答、又為何拒絕;這一堂,我們把問題往前推了一步。

當模型只能輸出文字,答錯的代價大多還停在螢幕上。但當它能讀檔案、查信件、呼叫 API,甚至操作真實系統,錯誤就不再只是一句不可靠的答案,而可能直接變成一個已經執行的動作。

這時真正要問的,也就不只是「模型會不會被騙」,而是:它在動手以前,能不能分辨眼前這道命令究竟來自使用者、系統,還是藏在資料裡的攻擊者?

課堂網站:https://ais3-2026.sectools.tw

課堂 Lab:https://github.com/stwater20/AIS3-2026-Material


一、從回答問題,到真的採取行動

我們平常使用聊天模型,大多是在問問題:請它解釋一段程式、整理一份報告,或幫忙找出文字裡的重點。

Agent 不太一樣。除了語言模型本身,它還多了工具、記憶、規劃與執行能力。它可以瀏覽網頁、讀寫檔案、寄信、安排工作,甚至在沒有人逐步指揮的情況下,自己把一個目標拆成多個步驟完成。

這當然很方便,但它也改變了風險的單位。

以前我們擔心模型「說錯話」;現在還得擔心它「做錯事」。一段錯誤內容可以被人看見、檢查與修正,但一個已經送出的請求、刪除的資料,或外洩的憑證,不一定還有回頭的機會。

從顧問、助手,一路走到自主代理

Agent 並不是一夕之間就變成全自動。最初的 Consultant AI 只提供建議,決定與執行都留給人;到了 Cockpit,模型被接進工作介面,能把資訊整理好,卻仍不直接動手。再往前一步是 Copilot,模型可以提出或執行動作,但關鍵步驟仍需要人工確認。Autopilot 則只需要一個目標,便能自行規劃並完成多個步驟;到了 Sovereign,連何時行動、怎麼拆解任務,都有更大的自主空間。

越往後走,人的角色就越從「逐步操作」退到「設定目標與監督結果」。能力是一路增加的,錯誤能走多遠也一樣。真正決定風險的,不只是模型聰不聰明,而是它拿到了哪些工具、哪些權限,以及每一個高後果動作之前,還有沒有人或系統能把它停下來。

工具放大的不只是能力

工具本身沒有善惡。搜尋、檔案系統、Shell、資料庫與訊息服務,本來就是我們每天都在使用的能力。問題在於,當這些能力被交給 Agent,語言模型產生的內容便可能直接成為下一個系統的輸入。

模型輸出的 tool call,看起來只是一段結構化資料,但從安全角度來看,它其實更接近一段尚未執行的程式。只要參數、目標或權限有一處判斷錯誤,影響的就會是外部世界。

因此,Agent 的安全不能只靠 system prompt 裡的一句「不要做危險的事」。提示詞是指令,不是權限系統,更不是最後一道防線。


二、Agent 的三個攻擊面

要理解 Agent 為什麼難以保護,可以先把攻擊面拆成三個部分:它讀進來的內容、它準備執行的動作,以及它所處的整套系統。

輸入與 Context:每一段文字都可能夾帶指令

模型看到的 context,不只包含使用者剛輸入的那句話。裡面可能還有 system prompt、先前的對話、工具回傳結果、網頁內容、檔案、郵件,以及從向量資料庫取回的記憶。

對人來說,文件裡的文字只是「資料」;對語言模型來說,它同時也可能長得像「指令」。

這就是間接提示詞注入(Indirect Prompt Injection)麻煩的地方。攻擊者不一定需要直接跟 Agent 對話,只要把惡意指令藏在 Agent 之後會讀到的工單、網頁、PDF 或郵件裡,就有機會讓內容越過原本的信任邊界。

常見的防線只檢查最新一輪使用者輸入,卻直接相信整段對話歷史。於是攻擊者若能偽造先前訊息,就可能先在 context 裡安排一段「使用者已經授權」「系統已經確認」的劇情,再讓最後一句看起來完全無害。

換句話說,最後一個 prompt 沒有惡意,不代表整段 context 值得信任。

輸出與工具:模型提案,不等於系統批准

第二個攻擊面,是模型產生的 tool call。

即使模型本身沒有打算做壞事,工具參數仍可能被 prompt injection、格式解析錯誤、中介服務或外部套件改寫。若系統看到 tool call 就直接執行,等於把語言模型的每一次猜測都當成正式授權。

真正穩健的做法,是把「模型想做什麼」與「系統允許做什麼」分開。模型只能提出動作;能不能執行,還要經過另一層確定性的政策判斷。

所處系統:模型之外,還有供應鏈與權限

Agent 並不是單獨運作。模型前後通常還接著 API 路由、MCP Server、瀏覽器、外掛、套件、身分系統與執行環境。任何一層被入侵、設定錯誤或取得過大的權限,都可能把模型原本有限的錯誤放大。

這裡最值得警覺的組合,是 Simon Willison 所整理的 Lethal Trifecta:Agent 能讀取不可信任的外部內容、能存取私有或敏感資料,又能對外採取行動或傳送資訊。三項能力分開看都很常見,放在同一個 Agent 身上卻非常危險。因為攻擊者可以把指令藏在外部內容裡,讓 Agent 讀取私有資料,再利用訊息、網址或其他工具把資料送出去。

這也說明了為什麼「模型有沒有拒絕」並不是完整答案。只要架構仍同時提供這三項能力,一次成功的繞過就可能造成實際損害。


三、防線要放在模型外面

Agent 安全沒有一個可以解決所有問題的萬用提示詞。比較務實的方向,是假設模型可能判斷錯誤,然後讓整套系統仍有能力把錯誤攔在執行以前。

對整段 Context 驗證來源與完整性

如果對話歷史由前端送回後端,就不應直接相信。系統可以用 HMAC 等機制替伺服器建立的歷史訊息簽章,載入時驗證每一段內容,並捨棄來源不明或被修改過的紀錄。

但這裡還有一個很容易被忽略的差別:簽章只能證明內容在傳輸途中沒有被竄改,不能證明內容本身是安全的。

如果惡意指令已經透過合法寫入流程進入記憶或資料庫,下一輪被取回時,它同樣可以帶著正確簽章出現在 context 裡。這類二階注入(Second-order Injection)或記憶投毒(Memory Poisoning),真正要守的是寫入路徑:資料從哪裡來、寫入前是否檢查、取回時是否保留來源標記,以及不可信內容能不能被隔離或降權。

在工具前面加一道 Policy Gate

每一次 tool call 都應被當成不可信輸入。Policy Gate 不需要跟模型一起「理解語意」,它只要依照清楚、可稽核的規則做決定:低風險、範圍明確而且符合既定條件的動作可以允許;涉及敏感資料、外部傳送或不可逆操作的動作交給人工確認;超出允許清單、權限或安全政策的動作則直接拒絕。

例如,讀取公開文件可以自動執行,但傳送訊息、修改權限、刪除資料與執行 Shell,就應有更嚴格的參數限制,必要時要求人工確認。

這道防線的重點,是由確定性的程式碼做最後決定,而不是再問另一個模型「你覺得這安全嗎?」

假設沙箱裡的程式一定有機會被執行

只要 Agent 能執行程式,就應把 Remote Code Execution 視為威脅模型裡的既定條件。沙箱的任務不是保證永遠不會出現 RCE,而是即使程式真的跑起來,也拿不到主機憑證、碰不到不必要的檔案、無法任意連線,更不能把影響帶出隔離範圍。

最小權限、短效憑證、網路出口限制、唯讀檔案系統、資源上限與完整稽核紀錄,這些看起來都是傳統資安控制,到了 Agent 時代反而更加重要。

讓攻擊變得昂貴,也讓測試能夠重複

多輪攻擊不一定一開始就提出危險要求。它可以先討論除錯、格式或測試資料,逐步建立上下文,最後才把真正的目標包裝成「前面流程的自然延續」。因此,防線不能只看單輪結果,還要觀察整段對話裡的目標是否逐漸偏移。

Rate limit、Captcha 與異常行為偵測未必能消滅攻擊,卻能提高自動化探索與大量重試的成本。另一方面,團隊也需要把攻擊案例整理成可重複執行的測試,而不是只在上線前隨手問幾個危險問題。OWASP AI Testing Guide 的價值正在這裡:把提示詞注入、工具濫用、資料外洩與代理行為納入一套可以持續驗證的測試流程。


Lab:讓 Agent 洩漏「不該說的祕密」

這次 Lab 建立了一個簡化的 SupportBot。它能讀取客服工單、查詢內部資料,並透過工具傳送訊息;系統裡則放了一組虛構的測試金鑰 ACME-4471

所有工具與資料都是模擬的,目標不是把 Lab 做成 CTF,而是讓大家直接看到:同一個祕密,可以從 Agent 的三種不同信任錯誤中流出去。

Part A:惡意指令藏在工單裡

第一部分把攻擊指令藏進客服工單。SupportBot 原本只是要讀取工單、協助處理問題,卻把工單裡的文字當成更高優先的命令,最後試圖呼叫 send_message 傳出測試金鑰。

這是一個標準的間接提示詞注入:使用者沒有直接要求外洩資料,真正的攻擊者藏在 Agent 讀取的內容裡。

加入 Policy Gate 後,即使模型仍產生危險的 tool call,系統也能在執行前檢查目的地、資料類型與操作風險。這個差異很重要:安全不必建立在「模型永遠不犯錯」的前提上。

Part B:偽造一段早已取得授權的歷史

第二部分展示的是 context 本身的問題。攻擊者偽造先前對話,讓歷史看起來像是管理員已經驗證身分,也已經授權輸出真實金鑰;最後一輪只需要用一句普通的「請繼續」收尾。

如果 guardrail 只檢查最新訊息,這一輪幾乎沒有可疑之處。真正改變模型判斷的內容,早就埋在前面的假歷史裡。

Lab 接著替伺服器建立的歷史加上 HMAC 簽章,拒絕載入任何無法驗證的紀錄。這可以防止前端任意改寫過去,但也留下前面提過的提醒:有簽章只代表資料沒有被偷偷修改,不代表最初寫進去的內容就可信。

Part C:不是一次突破,而是慢慢把界線推走

第三部分使用多輪 Crescendo 攻擊。攻擊者不直接索取金鑰,而是從測試流程、輸出格式與除錯情境開始,一步一步把「使用真實值」包裝成完成任務所需的合理動作。

這類攻擊之所以棘手,是因為每一輪單獨看都可能不夠危險。真正的變化發生在整段對話:原本的目標被逐漸改寫,模型也在先前內容的推動下,一步步接受新的前提。

因此,單輪拒絕不等於系統安全。防線需要記錄跨輪風險、限制敏感資訊的輸出路徑,並對高風險動作採取預設拒絕。Rate limit 則可以減少攻擊者大量試探、反覆修正話術的空間。


課後延伸

這次課堂的實作放在 Lab 2:Agent Security。Agent 同時接觸不可信內容、私有資料與外部通訊時的風險,可以接著讀 Simon Willison 的 The lethal trifecta for AI agents;如果要把攻擊案例整理成可以重複驗證的測試,則可以參考 OWASP AI Testing Guide。至於為什麼只擋住已知攻擊仍然不夠,The Attacker Moves Second 從自適應攻擊者的角度,重新檢驗了 jailbreak 與 prompt injection 防線。


寫到最後,其實只剩一句話:

工具,從來不是問題。真正危險的,是 Agent 在執行命令以前,未能分辨那道聲音究竟來自誰;而系統又剛好把分辨錯誤的代價,直接變成了現實。

You may also like