安全防护体系:当 Agent 拥有终端时如何防止「做出格」的事
Hermes 如何用工具守卫、危险命令审批、敏感路径保护、智能审批四道防线,约束 Agent 的破坏力
通过 Hermes 探秘 Agent 工程 | 第 5 篇 · 查看全部
[系列文章导航]
| # | 文章 | 定位 |
|---|---|---|
| 1 | Agent Loop:Agent 的核心执行循环 | 入口 |
| 2 | System Prompt:身份、上下文与策略的三层架构 | 认知层 |
| 3 | 工具系统:从注册到调度 | 工具层 |
| 4 | 工具调度系统:从注册到执行的完整生命周期 | 调度层 |
| 5 | 安全防护体系:当 Agent 拥有终端时如何防止「做出格」的事 | 安全层 |
| 6 | 沙箱与代码执行:让 Agent 安全跑代码的 RPC 架构 | 执行层 |
| 7 | 上下文压缩:让 Agent 在有限窗口里「记得住」 | 记忆层 |
| 8 | 记忆系统:跨会话持久化的工程实现 | 记忆层 |
| 9 | 技能系统:Agent 如何把经验变成可复用的程序化记忆 | 记忆层 |
| 10 | Provider 抽象层:让 Hermes 同时驾驭 30+ 个 LLM 提供商 | 模型层 |
| 11 | Gateway 网关:连接 20+ 平台的统一消息路由 | 接入层 |
| 12 | 多 Agent 协作:委托、调度与看板 | 协作层 |
问题:Agent 有「手」也有「破坏力」
上一篇文章,我们看到了 Hermes 的工具调度系统如何让 Agent 高效地「做事」。但一个不愿忽视的问题是:当 Agent 拥有 terminal 权限时,它也能执行 rm -rf /。
Agent 的安全风险来自几个层面:
- 循环失控:模型陷入死循环,反复调用同一个失败的工具,消耗 API 额度(详见 第 4 篇:工具调度系统)
- 破坏性命令:模型误操作或「幻觉」生成危险指令(
rm -rf /、git push --force到主分支) - 敏感路径访问:模型读取或修改安全策略文件本身(如
~/.ssh/、~/.hermes/config.yaml) - 错误信息注入:工具返回的错误字符串里包含
</tool_call>等结构标记,欺骗模型进入错误状态
Hermes 用四道防线构建了纵深防御体系。
第一道防线:工具调用守卫(Tool Guardrails)
三类循环检测
ToolCallGuardrailController 跟踪每轮的工具调用模式,检测三种循环:
| 类型 | 含义 | 触发条件(默认) |
|---|---|---|
| Exact Failure Loop | 同一工具 + 同一参数连续失败 | warn ≥ 2 次 / block ≥ 5 次 |
| Same Tool Failure Loop | 同一工具连续失败(不论参数) | warn ≥ 3 次 / halt ≥ 8 次 |
| No Progress Loop | 幂等工具反复返回相同结果 | warn ≥ 2 次 / block ≥ 5 次 |
签名机制
「相同的工具调用」不是通过字符串比对来识别的——Hermes 会对参数做规范化处理:
canonical = json.dumps(args, sort_keys=True, separators=(",", ":"))
signature = sha256(canonical) # 稳定、不可逆、不暴露参数值
两种守卫模式
警告模式(默认):不阻止执行,只是在工具结果后追加一条提示。模型看到这条消息后应该改变策略。
硬停止模式(opt-in):通过配置 hard_stop_enabled: true 开启。当循环达到阈值,直接返回 block 或 halt 决策。
工具分类
- 幂等工具(
IDEMPOTENT_TOOL_NAMES):read_file、search_files、web_search、browser_snapshot等——重复返回相同结果说明模型在「原地打转」 - 变更工具(
MUTATING_TOOL_NAMES):terminal、execute_code、write_file、patch等——连续调用可能是正常的重试逻辑
第二道防线:危险命令审批
三种审批模式
| 模式 | 行为 | 适用场景 |
|---|---|---|
manual | 必须人工确认(默认) | 日常使用 |
smart | 用辅助 LLM 自动判断 | 高频交互、信任环境 |
off | 不审批 | 高风险—仅推荐沙箱环境使用 |
危险模式匹配
approval.py 定义了一系列正则表达式来检测命令中的危险操作:删除类(rm -rf)、强制推送类(git push --force)、磁盘操作类(dd、mkfs)、Fork 炸弹、系统路径写入等。
macOS 特殊处理
macOS 的系统路径比较特殊——/etc、/var 是 /private/etc、/private/var 的符号链接。Hermes 显式匹配了两种形式,防止通过符号链接绕过保护。
第三道防线:敏感路径保护
| 路径模式 | 原因 |
|---|---|
~/.ssh/ | SSH 私钥——泄露意味着服务器沦陷 |
~/.hermes/.env | 环境变量——可能包含 API 密钥 |
~/.hermes/config.yaml | Agent 的安全策略本身——如果 Agent 能自行关闭审批…… |
*.env、*.env.* | 项目级环境变量文件 |
~/.netrc、~/.pgpass 等 | 凭证文件 |
自指保护:config.yaml 本身既是安全策略的载体,也是被保护的对象。
第四道防线:工具结果清洗
_sanitize_tool_error() 对错误字符串做清洗——去除 framing tokens(如 </tool_call>、Triple backticks)、转义 CDATA 标记、防止 fence tokens 出现在错误文本中。
四道防线的协同工作
模型发出 tool_calls
│
▼
┌─────────────────────────────────────────────┐
│ Tool Guardrails (per-turn 循环检测) │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 危险命令审批 (terminal 专用) │
│ ├─ 危险模式匹配 │
│ ├─ 敏感路径检查 │
│ ├─ 审批模式分支 (manual / smart / off) │
│ └─ 白名单检查 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 前置 Checkpoint (Git snapshot) │
│ ├─ write_file / patch → 确保可回滚 │
│ └─ destructive terminal → 确保可回滚 │
└─────────────────────────────────────────────┘
│
▼
工具实际执行
│
▼
┌─────────────────────────────────────────────┐
│ 后置处理 │
│ ├─ _sanitize_tool_error() → 清洗错误字符串 │
│ ├─ post_tool_call hook │
│ └─ 工具结果写入消息历史 │
└─────────────────────────────────────────────┘
下一篇:沙箱与代码执行:让 Agent 安全跑代码的 RPC 架构 — execute_code 工具如何在隔离环境中安全运行代码