跳到主要内容

Lab 02 · Tool Gate:批准必须绑定动作

用 Schema、allow/ask/deny Policy、HMAC 批准令牌与审计日志,阻止参数漂移、重放和越权工具调用。

本章任务

要回答的问题

用户批准 write_record 后,怎样保证执行的仍是同一用户、同一工具和同一组参数?

读完你能

  • 把参数校验、策略决策与执行拆成三个独立门
  • 将批准令牌绑定到 actor、tool、arguments 与过期时间
  • 检测参数漂移、令牌重放与 deny 工具调用
适合现在读
正在设计 Tool Dispatcher、人工审批、Policy Engine 或高风险工具的工程师
先修知识
能读懂结构化 Tool Call;理解哈希、过期时间与 nonce 的用途
实践产物
一个可运行 Tool Gate、七个安全用例和逐动作审计日志
证据边界
示例 Secret 与内存 nonce 仅用于教学;生产环境需要密钥管理、持久化重放保护和真实身份系统

用户批准写 safe-note,执行时却变成 secrets.env

Section titled “用户批准写 safe-note,执行时却变成 secrets.env”

模型请求:

{"tool":"write_record","arguments":{"record_id":"safe-note","value":"approved content"}}

用户点击批准以后,下一轮 Context 或恶意中间层把 record_id 改成 secrets.env。如果批准只是一枚布尔值 approved=true,Dispatcher 仍会执行漂移后的动作。

本实验要求批准令牌绑定四件事:actor、tool、canonical arguments hash 与 expires_at,并用 nonce 阻止同一令牌再次使用。

  1. Schema Gate:字段必须完全匹配,类型正确,不接受多余或缺失参数。
  2. Policy Gateread_record=allowwrite_record=askdelete_record=deny
  3. Approval Gate:只有 ask 动作需要令牌;令牌必须与当前动作完全一致且未过期、未重放。

任何拒绝都写进 audit.jsonl。审计不仅记录执行成功,还要记录拒绝原因,否则无法区分模型格式错、策略拒绝与批准失效。

Terminal window
python3 public/lab-assets/tool-gate.py

输出应包含:

{
"approval": "approval_required",
"approved_write": "executed",
"argument_drift": "arguments_drift",
"delete": "denied",
"read": "executed",
"replay": "replay",
"schema": "rejected"
}

然后查看:

.agent-mechanics-lab/tool-gate/audit.jsonl

每一条调用都应有 actor、tool、arguments、status 和 reason。批准令牌本身也会被记录;生产系统通常应只记录令牌摘要,避免泄露可重放凭据。

依次加入以下攻击:

  • 把 actor 从 user-42 改成 user-99
  • 把 tool 从 write_record 改成另一个 ask 工具;
  • 将过期时间设为过去;
  • 在参数中加入 Schema 没声明的 force=true
  • 让两个进程同时消费同一 nonce。

前四项应被当前脚本拒绝。第五项会暴露内存 set 的局限:跨进程重放保护必须落到数据库唯一约束或共享缓存的原子操作。

生产路径可以拆成:

model output
→ JSON parse
→ schema validation
→ identity and scope lookup
→ policy decision: allow | ask | deny
→ action-bound approval
→ sandbox / execution host
→ result persistence
→ audit event

批准发生在执行前,但它不是最后一道安全边界。即使 Approval Gate 有 Bug,执行宿主仍应限制文件、网络、身份和资源。

验收:批准不是同意某类动作,而是同意这一次动作

Section titled “验收:批准不是同意某类动作,而是同意这一次动作”

通过标准:

  • 漂移后的参数不能复用原令牌;
  • 同一令牌不能执行两次;
  • deny 工具即使携带合法签名也不能执行;
  • Schema 错误发生在 Policy 之前;
  • 审计日志覆盖 allow、ask、deny、rejected 与 replay。

把这五项变成自动测试后,再接 UI 按钮和真实 Tool Executor。

展开实验复盘与加分项
  • 为什么批准令牌不能只绑定 tool name?
  • Canonical JSON 如果跨语言不一致,会造成什么问题?
  • nonce 应在什么时候标记为已使用:验证前、执行前还是提交后?
  • UI 展示参数与实际哈希参数不一致时,谁负责阻止?
  • 加分项:把 used_nonces 改成 SQLite 唯一表,并写两个并发进程争用同一令牌的测试。