工具调用安全审查链(Inspector 模式)
工具调用安全审查链(Inspector 模式)
学习目标
读完本章后,你将能够:
- 理解 Inspector 模式在工具执行前的安全审查架构
- 设计多层 Inspector 的串行审查流水线
- 实现只能升级不能降级的权限覆盖逻辑
- 评估不同 Inspector 的安全/延迟权衡
前置知识
核心概念
1. 为什么需要审查链
Agent 在执行工具(如 Shell 命令、文件读写、网络请求)前,需要回答多个安全问题:
- 用户是否授权此操作?(权限)
- 工具参数中是否包含注入攻击?(安全)
- 此操作是否会向外部发送敏感数据?(出口)
- 是否是恶意的对抗性请求?(对抗)
- 是否陷入重复调用循环?(重复)
将这些问题交给单一检查函数会导致:逻辑耦合、难以扩展、审计困难。Inspector 模式将每种检查独立为可插拔的模块。
2. Inspector 架构
3. 核心接口
trait ToolInspector { fn name(&self) -> &str; // 审查器名称 fn is_enabled(&self) -> bool; // 是否启用 async fn inspect(&self, ctx) -> Vec<InspectionResult>; // 执行审查}
enum InspectionAction { Allow, // 允许执行 Deny, // 拒绝 RequireApproval(Option<String>), // 需要用户确认,附带警告信息}
struct InspectionResult { tool_request_id: String, action: InspectionAction, reason: String, confidence: f32, // 审查置信度 inspector_name: String, finding_id: String,}4. 五层 Inspector
| Inspector | 检查内容 | 方法 | 默认行为 |
|---|---|---|---|
| Permission | Goose 模式 + 用户权限规则(AlwaysAllow/NeverAllow/AskBefore) | 规则匹配 | 根据模式决定 |
| Security | 模式匹配的 Prompt 注入检测(如 curl | bash) | 正则/模式匹配 | 检测到 → RequireApproval |
| Adversary | LLM 驱动的对抗性审查 | 调用 LLM 判断 ALLOW/BLOCK | 出错时 → Allow(fail-open) |
| Egress | 检测 Shell/Web 工具中的出站流量(URL、SSH、SCP、S3 推送等) | 正则提取 | 仅信息标记,不阻断 |
| Repetition | 检测同一工具 + 同参数的重复调用 | 计数 + 窗口 | 超过阈值 → 警告/阻断 |
设计模式详解
串行审查 + 结果合并
Inspector 按注册顺序串行执行,每个 Inspector 独立审查同一批工具调用,返回各自的 Vec<InspectionResult>。
合并逻辑(只能升级不能降级):
关键安全原则:任何 Inspector 都可以阻止工具执行(escalate),但没有任何 Inspector 可以解除其他 Inspector 的阻止(de-escalate)。这保证了「最严格的 Inspector 决定上限」。
Permission Inspector:权限基线
Permission Inspector 是第一个执行的 Inspector,建立权限的初始状态:
- Auto 模式:所有工具默认 approved
- Approve 模式:所有工具需要用户确认
- SmartApprove 模式:LLM 缓存辅助的权限判断
- Chat 模式:跳过所有工具调用
此外还处理用户定义的 AlwaysAllow / NeverAllow / AskBefore 规则,以及对「一等扩展」的特殊权限(不受权限管理器约束)。
Security Inspector:Prompt 注入检测
Security Inspector 使用模式匹配检测常见的 Prompt 注入攻击:
curl | bash类管道执行- 隐藏的危险命令
- 试图绕过安全限制的指令
检测到可疑模式时,返回 RequireApproval 并附带格式化的安全告警消息,展示给用户确认。
Adversary Inspector:LLM 对抗审查
Adversary Inspector 是最高级的审查层,使用 LLM 本身来判断工具调用的安全性:
- 读取用户自定义规则文件
~/.config/goose/adversary.md - 将工具调用描述 + 原始任务 + 近期用户消息发送给 LLM
- LLM 返回
ALLOW或BLOCK
Fail-Open 策略:当 LLM 调用失败时(网络错误、API 限流),Adversary Inspector 默认返回 Allow,而非阻断所有工具调用。这是可用性优先的设计——安全审查不应成为系统不可用的原因。
Egress Inspector:出口流量分析
Egress Inspector 扫描 Shell 命令和 Web 工具参数中的出站流量特征:
- URL、HTTP 请求
- SSH 连接
- SCP/SFTP 文件传输
- Docker push
- npm/cargo/pip publish
- S3 / GCS 上传
设计定位:Egress Inspector 始终返回 Allow,置信度为 0.0。它不做阻断,只做信息标记——将检测到的出站目标记录在 InspectionResult 中,供审计日志或 UI 展示使用。
用户确认与持久化
对于需要确认的工具:
- 发送
Message::assistant().with_action_required(...)给前端,附带安全告警 - 等待
tool_confirmation_router.register()返回用户决策 - 用户选择:
AllowOnce:本次允许AlwaysAllow:本次允许 + 持久化为AlwaysAllow规则AlwaysDeny:本次拒绝 + 持久化为NeverAllow规则
问题与规避
Fail-Open vs Fail-Closed
问题:当某个 Inspector 自身发生故障时(如 LLM 不可用),应该默认允许还是默认拒绝?
对策:
- Security Inspector:Fail-Open —— 注入检测是额外保护,不应阻塞正常使用
- Adversary Inspector:Fail-Open —— LLM 审查失败时回退到其他 Inspector
- Permission Inspector:Fail-Closed —— 权限是基线,无法判断时应要求确认
- Egress Inspector:始终 Allow —— 仅用于审计
设计启示:安全链中的每一层都应该明确自己的故障模式。将「最关键的检查」(权限)放在最前面,「额外增强检查」(注入检测、对抗审查)放在后面且采用 fail-open。
审查延迟累积
问题:每层 Inspector 都增加延迟,特别是 Adversary Inspector 需要额外调用 LLM。
对策:
- Inspector 支持
is_enabled()开关,可按需禁用 - 轻量 Inspector(正则匹配)在前,重型 Inspector(LLM 调用)在后
- 可以配置 Inspector 超时时间
审查规则的可解释性
问题:用户不知道某个工具为什么被阻止。
对策:
- 每个
InspectionResult包含reason和inspector_name RequireApproval附带格式化的告警消息- UI 展示是哪个 Inspector 触发的阻止及原因
设计取舍
串行审查 vs 并行审查
| 维度 | 串行审查 | 并行审查 |
|---|---|---|
| 延迟 | 各层累加 | 取最慢的一层 |
| 依赖关系 | 后层可以看到前层结果 | 各层独立 |
| 短路优化 | 可以提前终止(如第一个就 Deny) | 必须等待全部完成 |
| 实现复杂度 | 低 | 高(需要结果合并) |
大多数 Agent 系统选择串行审查,因为:(1)Inspector 数量通常不多(3-5 个);(2)前层审查结果可以为后层提供上下文;(3)可以在遇到 Deny 时短路停止。
模式匹配 vs LLM 审查
| 维度 | 模式匹配(Security Inspector) | LLM 审查(Adversary Inspector) |
|---|---|---|
| 速度 | 极快(正则) | 慢(需要 LLM 调用) |
| 覆盖率 | 只能检测已知模式 | 可以理解语义 |
| 误报率 | 低(规则精确) | 较高(LLM 主观判断) |
| 维护成本 | 需要持续更新规则库 | 依赖 LLM 能力 |
推荐策略:模式匹配作为第一道快速防线,LLM 审查作为深度补充。两者结合可以兼顾速度和覆盖率。
Inspector 模式 vs 单一权限检查
| 维度 | 单一权限检查 | Inspector 链 |
|---|---|---|
| 实现复杂度 | 低 | 中 |
| 可扩展性 | 差(改一处影响全局) | 好(独立插拔) |
| 审计能力 | 弱 | 强(每层独立日志) |
| 适用场景 | 简单 Agent | 企业级安全需求 |
当 Agent 只需要区分「允许/拒绝」时,单一权限检查足够。当需要多维度安全审查(注入检测、对抗分析、出口流量)时,Inspector 链的可维护性和可审计性明显更优。