當模型輸出從文字變成可造成 side effect 的 Tool Call,哪些新的 principal、trust boundary 與 enforcement point 必須出現?
假設企業內有一個「客服工作助理」。使用者輸入:「請找出訂單編號 4821 的延遲原因,如果確認是倉庫問題,就建立一張補寄單,並通知客戶。」
傳統 chatbot 可能只回覆一段建議文字;Agent 則可能先查詢訂單,再呼叫倉儲 API 建立補寄單,最後呼叫通知工具寄出訊息。對使用者而言,兩者都像是在「回答」;對企業而言,後者已經跨過了從資訊處理到改變外部狀態的界線。
這不是在判斷模型是否聰明,也不是假設模型一定惡意。即使模型完全正常,模型輸出仍是未經授權的建議,不能直接等同於執行權力。
傳統 IAM 常把問題簡化成「某個 subject 能否存取某個 resource」。Agent 場景多了三個會改變安全邊界的因素:
NIST 對 tool-use agent 的整理也把「能否寫入」、「是否可逆」、「自主程度」及可觀測性列為重要的工具使用與限制維度;這正是不能只以「有沒有登入」描述 Agent 風險的原因。NIST:Lessons Learned from the Consortium—Tool Use in Agent Systems
所以本文不會把 OAuth、JWT 或 RBAC 當成主角,而是先問三件事:Agent 是誰?它代表誰?它憑什麼執行這個具體 Action?
最容易出現的設計如下:Agent runtime 同時持有 WAREHOUSE_API_TOKEN 和 MAIL_API_TOKEN,模型回傳 JSON 後,程式依照 tool 欄位直接呼叫對應 API。
User prompt → Model → tool name + parameters → Tool API
↘ shared credential
這裡至少有五個問題:
order_id=4821 改成另一筆訂單,或把通知收件者改成外部地址。這是典型的 confused deputy:模型或上游程式拿著比目前請求更大的權力,替另一個主體使用了資源。問題不在於「模型是否可信」,而在於真正的 enforcement point 太晚,甚至根本不存在。
純文字 chatbot 的主要資料流是:
User → UI → Model → Text response → User
模型產生的文字可能錯誤、誤導或包含不安全建議,但它本身沒有直接改變訂單、資料庫或郵件系統的能力。應用程式仍可在顯示、儲存或送出前加入檢查。
Agent 需要另外處理執行平面:
User → Agent runtime → Model
↓ intent / plan / proposed Action
Tool Gateway / PEP → Tool / API → Resource
↑
PDP decision
這裡至少要分開以下角色:
NIST SP 800-207 將 Policy Enforcement Point 定義為控制主體與企業資源連線、監控並可終止連線的元件;套到 Agent,Tool Gateway 正是把「模型想做什麼」與「資源實際允許什麼」隔開的邊界。NIST SP 800-207:Zero Trust Architecture

此設計把模型輸出的 tool 與 parameters 當成呼叫 API 的充分條件。它沒有獨立的 Action policy,也沒有可靠的位置確認「誰」提出請求、「代表誰」以及「為什麼這個參數可以造成這個副作用」。
即使在 API 端加上登入檢查,仍只回答了 authentication:「你持有 credential 嗎?」;它沒有回答 authorization:「這個 Agent 是否被允許為這個 Task 對這筆訂單建立補寄單?」
推薦把模型輸出視為 proposed Action,交給不可繞過的 Gateway 重新驗證:

一次決策至少應帶有以下資料:
{
"subject": "user:alice",
"actor": "agent:customer-ops/instance-7",
"task": "task:4821-delay-resolution",
"action": "warehouse.create_reship",
"resource": "order:4821",
"constraints": {"reason": "warehouse_delay", "count": 1},
"decision": "allow",
"policy_version": "2026-08-12.1"
}
這不是要求每個系統立刻採用相同的 token 格式,而是要求架構上能分辨 User、Agent 與具體 Action。subject 表示任務代表誰,actor 表示實際執行的 Agent;兩者不能被一個共用 service account 壓平。
本日先畫出四個邊界:
因此 Identity Flow 應是「User Identity + Agent Identity + Task / Action context」一起抵達決策點,而不是 User token 被原封不動轉送,或 Agent 自報 X-Agent-Id 就被接受。
PDP 的最小決策單位應是具體 Action,而不是「Agent 能不能連上 MCP server」或「Agent 是否被加入工具清單」。例如:
| proposed Action | resource | decision | 理由 |
|---|---|---|---|
warehouse.get_order |
order:4821 |
Allow | 唯讀、Task 綁定該訂單 |
warehouse.create_reship |
order:4821 |
Allow with constraint | 僅限倉庫延遲、數量 1 |
warehouse.create_reship |
order:7730 |
Deny | 超出 Task resource scope |
mail.send |
外部收件者 | Approval required / Deny | 具有外部 side effect |
每個 decision 都應留下 correlation ID、subject、actor、Action digest、resource、policy version、decision、constraint 與 Tool outcome。這讓後續調查可以回答「誰代表誰做了什麼」,而不是只看到一筆模糊的 API log。
以下程式只使用 Python 標準庫,模擬同一個模型輸出。在 read-only chatbot 路徑,輸出只是文字;在 Agent 路徑,輸出必須先通過本地 Gateway 的逐 Action policy。將程式存成暫存檔執行即可,不需要安裝套件。
import json
model_output = {
"tool": "warehouse.create_reship",
"parameters": {"order_id": "4821", "reason": "warehouse_delay", "count": 1},
}
def chatbot_path(proposed):
return "建議執行:" + json.dumps(proposed, ensure_ascii=False)
def agent_gateway(proposed, task):
p = proposed["parameters"]
allowed = (
proposed["tool"] == "warehouse.create_reship"
and p["order_id"] == task["order_id"]
and p["reason"] == "warehouse_delay"
and p["count"] == 1
)
if not allowed:
return {"decision": "deny", "reason": "Action 不符合 task constraints"}
return {"decision": "allow", "resource": "order:" + p["order_id"]}
task = {"order_id": "4821"}
print("chatbot:", chatbot_path(model_output))
print("agent:", agent_gateway(model_output, task))
tampered = {**model_output, "parameters": {**model_output["parameters"], "order_id": "7730"}}
print("tampered agent:", agent_gateway(tampered, task))
預期結果:
chatbot: 建議執行:{"tool": "warehouse.create_reship", ...}
agent: {'decision': 'allow', 'resource': 'order:4821'}
tampered agent: {'decision': 'deny', 'reason': 'Action 不符合 task constraints'}
這個 PoC 沒有模擬真實模型、token 或 API server,因為本日要證明的不是某個產品的整合方式,而是 enforcement point 的位置:同一段輸出在沒有 side effect 的 data plane 與有 side effect 的 execution plane,必須走不同的安全路徑。
今天先證明 Agent 需要一條獨立的執行與授權邊界;但 Tool 到底應該把 Agent 視為使用者、應用程式,還是 workload?下一篇會拆開 User Identity、Agent Identity、Agent definition 與 runtime instance,回答「一個 Agent 到底算哪一種 security principal?」