IGNORE PREVIOUS INSTRUCTIONS… exfiltrate the API key 的页面。一行数据库记录里内嵌了一条指令。一个第三方
MCP 服务器交回一个被精心构造来引导模型的结果。模型把那个结果
当作可信上下文来读取并据此行动——调用一个新工具、泄露一个
密钥,或在运行中途改变路线。
这就是工具响应篡改:攻击面不是用户输入的提示词,而是一个
工具返回的结果。模型把工具输出当作真理,因此一个被投毒的结果
就是一条控制通道。
所以防御不是”清理被投毒的结果”。它是控制其爆炸半径:筛查
模型接下来说的任何内容、把守它接下来试图采取的任何动作,
并留下一份展示这次转向(pivot)的审计追踪。
1. 为何不安全的工具输出难以中和
一个工具结果在设计上就是不透明的。它可以是 HTML、JSON、一个 文件、数据库的一行,或来自一个远程 MCP 服务器的响应——其中 任何一个都可能携带攻击者控制的文本。你无法在不破坏合法载荷 的情况下用正则清理它,而模型也没有”这来自一个不可信工具,要 不信任它”的内建概念。 现实的姿态是在工具两侧而非其内部的一道信任边界:在模型作答之后
输出防护栏筛查模型的下一条消息——
它即将泄露的密钥、它正在回显的被注入指令。
在下一个动作之前
防火墙的允许列表把守模型读取被投毒
结果后发出的下一次工具调用。
留存记录
一个
audit 判定与防护栏 matches 信息流记录这次转向,因此
即便什么都没被拦截,一次被劫持的运行也是可见的。2. 防御一——对模型下一条回复的输出防护栏
当模型刚刚消费了一个工具结果时,它发出的下一个东西正是一次 成功注入显现之处:一个泄露的凭据、一条被回显的指令、一个偏离 策略的答案。一条输出阶段防护栏会在那条回复到达客户端之前 对其进行筛查。 把一条带输出阶段规则的防护栏附加到你的智能体所用的密钥上:guardrail_blocked 拒绝该响应——而
一次输出 block 会退还预先消耗的配额。这里有用的规则类型:
| 规则类型 | 捕获 |
|---|---|
pii / secrets | 被投毒结果诱导模型暴露出来的一条凭据或 PII。 |
llm_judge | 语义注入意图——“这条回复正在遵从一条内嵌指令”。一次裁判调用作为一条子项计费。 |
keyword / regex | 你种入上下文的已知外泄标记或金丝雀字符串。 |
输出
block 和 mask 在流式和非流式上都被执行。 在流式中,
扫描器会缓冲一个小的尾随窗口,这样一个被切分到多个 SSE 块的
模式仍能被捕获:一次 block 会在违规内容到达客户端之前中途
切断数据流,而一次 mask 会就地改写缓冲并发出脱敏后的前缀。
参见 防护栏参考。3. 防御二——防火墙允许列表把守下一个动作
一个说”现在调用shell.exec”的被投毒结果,只有在模型确实能
调用 shell.exec 时才要紧。防火墙会评估 response 执行面
——模型在其回复中发出的 tool_calls——因此注入试图引发的那个
动作是被对照你的策略来判定的,而不是攻击者的指令。
这就是让不安全工具输出可被幸存的那个控制:结果可以说任何话,
但下一次工具调用仍然必须通过你的允许列表。在 response
阶段编写一条 deny 规则,那个被引发的调用就会在它运行之前被
拦截:
pending_approval 规则是折中之选——
把被引发的调用挂起交给人工,而不是直接彻底拦截。完整的匹配
语言参见 防火墙规则参考,
HITL 审批。
防火墙策略写入需要 Developer+;读取(设置、策略、discovered
tools、simulate、预设)对每个 Member 开放。
4. 防御三——audit 判定让劫持可见
最糟糕的工具响应篡改是那种不触发任何拦截的——一个被投毒的 结果在被允许的范围内悄悄重定向一次运行。audit 判定正是
为此而生:它放行一次调用但记录它,因此一次在读取不可信结果后
转向的运行可以事后被重建。
audit是默认的default_verdict——观察一切、不拦截任何 东西,直到你知道正常是什么样子。- Runs & sessions 汇总展示一个智能体在一次对话中究竟做了 什么——不同的工具、判定细分、首次/末次出现——因此一个新颖的 工具到工具转移会显得突出。
- 异常检测会对照一个
学习到的基线标记一个
novel_path(本工作区从未做过的一次 工具转移)或一个retry_loop——即一次被甩离其惯常轨道的运行 的指纹。 - 防护栏 matches 记录每一条触发的输出阶段规则。当你需要 命中的子串用于分类排查时,在该防护栏上启用 Log raw content (默认关闭)。
先以影子模式上线一条策略。 一个按策略的
shadow_mode 标志
会把每个执行性判定降级为 audit,并给原因加上前缀
[shadow] would …,这样你就能在开始拦截真实流量之前,精确看到
哪些被引发的工具调用本会被拒绝。5. 把它组装起来
一次针对被投毒工具结果的、有防御的运行看起来是这样的:- 工具返回攻击者控制的文本。OrcaRouter 不会改动结果字节 ——这是设计如此。
- 模型读取它并发出下一条回复。一条输出防护栏筛查那条回复; 一个泄露的密钥或一条被注入的指令被拦截(配额退还)或 mask。
- 模型发出一次后续工具调用。防火墙在
response执行面上 对照你的允许列表判定它;一次不被允许或破坏性的调用被拒绝或 挂起待审批。 - 每一步都被记录——防火墙事件、运行汇总、异常信号和防护栏 matches——因此即便一次被允许但可疑的转向也是可见的。
6. 相关威胁与概念
提示注入
同一条控制通道,经由提示词而非工具结果到达。
MCP 工具投毒
恶意 MCP 服务器——包括经由一次
tools/call 投递的被投毒结果。数据外泄
阻止一个被引发的工具把数据发出去的 egress 规则。
危险工具调用
无论由什么引发,都拦截破坏性动作。
- 不安全输出——更广义地筛查 模型的响应,不止于工具篡改的情形。
- 过度自主权——从根本上限定 一个智能体能做什么,让一次劫持能抓取的东西更少。
- 执行模式——
auditvs 执行 vs 影子,以及何时各用哪种。 - 防护栏 vs 防火墙—— 哪个平面筛查文本、哪个把守动作。
