ByteNoteByteNote

字节笔记本

2026年6月21日

hermes教程-安全

API中转
¥120

概述

安全模型包含七个层次:

  1. 用户授权 — 谁可以与代理对话(白名单、私信配对)
  2. 危险命令审批 — 破坏性操作需要人在回路中
  3. 容器隔离 — 使用强化设置的 Docker/Singularity/Modal 沙箱
  4. MCP 凭据过滤 — MCP 子进程的环境变量隔离
  5. 上下文文件扫描 — 项目文件中的提示注入检测
  6. 跨会话隔离 — 会话之间无法访问彼此的数据或状态;定时任务存储路径经过强化,可抵御路径遍历攻击
  7. 输入清理 — 终端工具后端的工作目录参数根据白名单进行验证,防止 Shell 注入

危险命令审批

在执行任何命令之前,Hermes 会将其与精心策划的危险模式列表进行比对。如果匹配,用户必须明确批准。

审批模式

审批系统支持三种模式,通过 ~/.hermes/config.yaml 中的 approvals.mode 配置:

yaml
approvals:
  mode: manual                    # manual | smart | off
  timeout: 60                     # 等待用户响应的秒数(默认:60)
  cron_mode: deny                 # deny | approve — 定时任务遇到危险命令时的行为
  mcp_reload_confirm: true        # /reload-mcp 在使 MCP 工具缓存失效前询问
  destructive_slash_confirm: true # /clear, /new, /reset, /undo 在丢弃状态前提示

所有键的完整列表:

默认值控制内容
modemanual危险 shell 命令的审批策略 — 见下表。
timeout60Hermes 等待审批回复的超时秒数。
cron_modedeny定时任务在无头模式下触发危险命令提示时的行为。deny 阻止命令(代理必须寻找其他路径);approve 在定时任务上下文中自动批准所有内容。
mcp_reload_confirmtrue为 true 时,/reload-mcp 在重建 MCP 工具集之前询问。重建会使提供者提示缓存失效(工具模式位于系统提示中),因此下一条消息会重新发送完整的输入令牌。点击 Always Approve 的用户会将此键设为 false
destructive_slash_confirmtrue为 true 时,破坏性会话斜杠命令(/clear/new/reset/undo)在丢弃对话状态前提示。提供三个选项的对话框(批准一次 / 始终批准 / 取消),在 Telegram、Discord 和 Slack 上通过原生是/否按钮路由;其他平台使用文本回退。点击 Always Approve 的用户会将此键设为 false。TUI 使用自己的模态覆盖层(设置 HERMES_TUI_NO_CONFIRM=1 可选择退出)。
模式行为
manual(默认)始终提示用户批准危险命令
smart使用辅助 LLM 评估风险。低风险命令(例如 python -c "print('hello')")自动批准。真正危险的命令自动拒绝。不确定的情况升级为手动提示。
off禁用所有审批检查 — 相当于使用 --yolo 运行。所有命令无需提示即可执行。

警告

设置 approvals.mode: off 会禁用所有安全提示。仅在受信任的环境(CI/CD、容器等)中使用。

YOLO 模式

YOLO 模式会绕过当前会话中所有危险命令的审批提示。可以通过三种方式激活:

  1. CLI 标志:使用 hermes --yolohermes chat --yolo 启动会话
  2. 斜杠命令:在会话期间输入 /yolo 来切换开关
  3. 环境变量:设置 HERMES_YOLO_MODE=1

/yolo 命令是一个开关 — 每次使用都会切换模式:

text
> /yolo
  ⚡ YOLO 模式已开启 — 所有命令自动批准。请谨慎使用。

> /yolo
  ⚠ YOLO 模式已关闭 — 危险命令需要批准。

YOLO 模式在 CLI 和网关会话中均可用。内部会设置 HERMES_YOLO_MODE 环境变量,该变量在每次命令执行前被检查。

当 YOLO 激活时,Hermes 会显示两个持久的视觉提醒,以便用户难以忘记审批提示已被绕过:

  • 当 YOLO 已激活时,会话启动时显示红色横幅行:⚠ YOLO 模式 — 所有审批提示已绕过。当 YOLO 关闭时隐藏,以保持默认横幅整洁。
  • 状态栏中显示 ⚠ YOLO 片段,在所有宽度层级中实时更新,随着 YOLO 的开关而改变(富文本渲染器和纯文本回退)。

危险

YOLO 模式会禁用会话中所有危险命令的安全检查 — 除了硬性阻止列表(见下文)。仅当您完全信任生成的命令时使用(例如,在一次性环境中经过充分测试的自动化脚本)。

对于破坏性会话斜杠命令(/clear/new/reset/undo/quit --delete/exit --delete 是别名),CLI 也会在运行前提示确认。请参阅斜杠命令 — 破坏性命令的确认提示

硬性阻止列表(始终开启的底线)

某些命令具有灾难性后果 — 不可逆的文件系统擦除、fork 炸弹、直接块设备写入 — Hermes 无论以下情况都拒绝运行:

  • --yolo / /yolo 已开启
  • approvals.mode: off
  • 定时任务在无头 approve 模式下运行
  • 用户明确点击“始终允许”

阻止列表是 --yolo 之下的底线。它在审批层甚至看到命令之前就触发,并且没有覆盖标志。当前涵盖的模式(非详尽;与 tools/approval.py::UNRECOVERABLE_BLOCKLIST 保持同步):

模式为何是硬性
rm -rf / 及明显变体擦除文件系统根目录
rm -rf --no-preserve-root /明确“是的,我指的是根目录”的变体
:(){ :|:& };:(bash fork 炸弹)使主机卡死直到重启
在已挂载的根设备上执行 mkfs.*格式化正在运行的系统
dd if=/dev/zero of=/dev/sd*将物理磁盘清零
将不受信任的 URL 通过管道传递给根文件系统顶层的 sh远程代码执行攻击向量过于宽泛,无法批准

如果您触发了阻止列表,工具调用会向代理返回解释性错误,并且不会执行任何操作。如果合法工作流需要这些命令之一(例如,您是擦除并重新安装管道的操作员),请在代理外部运行。

审批超时

当出现危险命令提示时,用户有可配置的时间来响应。如果在超时内没有响应,命令默认被拒绝(故障关闭)。

~/.hermes/config.yaml 中配置超时:

yaml
approvals:
  timeout: 60  # 秒(默认:60)

触发审批的模式

以下模式会触发审批提示(定义在 tools/approval.py 中):

模式描述
rm -r / rm --recursive递归删除
rm ... /在根路径中删除
chmod 777/666 / o+w / a+w全局/其他可写权限
chmod --recursive 配合不安全权限递归全局/其他可写(长标志)
chown -R root / chown --recursive root递归将所有者改为 root
mkfs格式化文件系统
dd if=磁盘复制
> /dev/sd写入块设备
DROP TABLE/DATABASESQL DROP
DELETE FROM(无 WHERE)无 WHERE 条件的 SQL DELETE
TRUNCATE TABLESQL TRUNCATE
> /etc/覆盖系统配置
systemctl stop/restart/disable/mask停止/重启/禁用系统服务
kill -9 -1杀死所有进程
pkill -9强制杀死进程
Fork 炸弹模式Fork 炸弹
bash -c / sh -c / zsh -c / ksh -c通过 -c 标志执行 shell 命令(包括组合标志如 -lc
python -e / perl -e / ruby -e / node -c通过 -e/-c 标志执行脚本
curl ... | sh / wget ... | sh将远程内容通过管道传递给 shell
bash <(curl ...) / sh <(wget ...)通过进程替换执行远程脚本
tee/etc/~/.ssh/~/.hermes/.env通过 tee 覆盖敏感文件
> / >>/etc/~/.ssh/~/.hermes/.env通过重定向覆盖敏感文件
xargs rmxargs 配合 rm
find -exec rm / find -delete带破坏性操作的 find
cp/mv/install/etc/将文件复制/移动到系统配置中
sed -i / sed --in-place/etc/原地编辑系统配置
pkill/killall hermes/gateway防止自我终止
gateway run 配合 &/disown/nohup/setsid防止在服务管理器之外启动网关

信息

容器绕过:当在 dockersingularitymodaldaytona 后端运行时,危险命令检查被跳过,因为容器本身就是安全边界。容器内的破坏性命令无法损害主机。

审批流程(CLI)

在交互式 CLI 中,危险命令会显示内联审批提示:

text
  ⚠️  危险命令:递归删除
      rm -rf /tmp/old-project

      [o]一次  |  [s]会话  |  [a]始终  |  [d]拒绝

      选择 [o/s/a/D]:

四个选项:

  • 一次 — 允许本次执行
  • 会话 — 允许此模式在会话剩余时间内执行
  • 始终 — 添加到永久白名单(保存到 config.yaml
  • 拒绝(默认)— 阻止命令

审批流程(网关/消息平台)

在消息平台上,代理将危险命令的详细信息发送到聊天中,并等待用户回复:

  • 回复 yesyapproveokgo 以批准
  • 回复 nondenycancel 以拒绝

运行网关时,环境变量 HERMES_EXEC_ASK=1 会自动设置。

永久白名单

通过“始终”批准的命令会保存到 ~/.hermes/config.yaml

yaml
## 永久允许的危险命令模式
command_allowlist:
  - rm
  - systemctl

这些模式在启动时加载,并在所有未来会话中静默批准。

提示

使用 hermes config edit 查看或从永久白名单中移除模式。

用户授权(网关)

当运行消息网关时,Hermes 通过分层授权系统控制谁可以与机器人交互。

授权检查顺序

_is_user_authorized() 方法按以下顺序检查:

  1. 按平台允许所有标志(例如 DISCORD_ALLOW_ALL_USERS=true
  2. 私信配对已批准列表(通过配对码批准的用户)
  3. 平台特定白名单(例如 TELEGRAM_ALLOWED_USERS=12345,67890
  4. 全局白名单GATEWAY_ALLOWED_USERS=12345,67890
  5. 全局允许所有GATEWAY_ALLOW_ALL_USERS=true
  6. 默认:拒绝

平台白名单

~/.hermes/.env 中设置允许的用户 ID,以逗号分隔:

bash
## 平台特定白名单
TELEGRAM_ALLOWED_USERS=123456789,987654321
DISCORD_ALLOWED_USERS=111222333444555666
WHATSAPP_ALLOWED_USERS=15551234567
SLACK_ALLOWED_USERS=U01ABC123
## 跨平台白名单(所有平台均检查)
GATEWAY_ALLOWED_USERS=123456789
## 按平台允许所有(谨慎使用)
DISCORD_ALLOW_ALL_USERS=true
## 全局允许所有(极其谨慎使用)
GATEWAY_ALLOW_ALL_USERS=true

警告

如果未配置任何白名单且未设置 GATEWAY_ALLOW_ALL_USERS,则所有用户都被拒绝。网关在启动时会记录警告:

text
未配置用户白名单。所有未授权用户将被拒绝。
在 ~/.hermes/.env 中设置 GATEWAY_ALLOW_ALL_USERS=true 以允许开放访问,
或配置平台白名单(例如 TELEGRAM_ALLOWED_USERS=your_id)。

私信配对系统

为了实现更灵活的授权,Hermes 包含一个基于代码的配对系统。无需预先提供用户 ID,未知用户会收到一个一次性配对码,机器人所有者通过 CLI 批准。

工作原理:

  1. 未知用户向机器人发送私信
  2. 机器人回复一个 8 字符的配对码
  3. 机器人所有者在 CLI 上运行 hermes pairing approve <platform> <code>
  4. 该用户在该平台上被永久批准

~/.hermes/config.yaml 中控制如何处理未授权的私信:

yaml
unauthorized_dm_behavior: pair

whatsapp:
  unauthorized_dm_behavior: ignore
  • pair 是默认值。未授权的私信会收到配对码回复。
  • ignore 静默丢弃未授权的私信。
  • 平台部分会覆盖全局默认值,因此您可以在 Telegram 上保持配对,同时让 WhatsApp 保持静默。

安全特性(基于 OWASP + NIST SP 800-63-4 指南):

特性详情
代码格式8 字符,来自 32 字符无歧义字母表(无 0/O/1/I)
随机性加密安全(secrets.choice()
代码 TTL1 小时过期
速率限制每个用户每 10 分钟 1 次请求
待处理限制每个平台最多 3 个待处理代码
锁定5 次失败批准尝试 → 1 小时锁定
文件安全所有配对数据文件 chmod 0600
日志记录代码永远不会记录到 stdout

配对 CLI 命令:

bash
## 列出待处理和已批准的用户
hermes pairing list
## 批准配对码
hermes pairing approve telegram ABC12DEF
## 撤销用户访问权限
hermes pairing revoke telegram 123456789
## 清除所有待处理代码
hermes pairing clear-pending

存储: 配对数据存储在 ~/.hermes/pairing/ 中,每个平台有 JSON 文件:

  • {platform}-pending.json — 待处理的配对请求
  • {platform}-approved.json — 已批准的用户
  • _rate_limits.json — 速率限制和锁定跟踪

容器隔离

当使用 docker 终端后端时,Hermes 对每个容器应用严格的安全强化。

Docker 安全标志

每个容器都使用以下标志运行(定义在 tools/environments/docker.py 中):

python
_BASE_SECURITY_ARGS = [
    "--cap-drop", "ALL",                          # 丢弃所有 Linux 能力
    "--cap-add", "DAC_OVERRIDE",                  # root 可以写入绑定挂载的目录
    "--cap-add", "CHOWN",                         # 包管理器需要文件所有权
    "--cap-add", "FOWNER",                        # 包管理器需要文件所有权
    "--security-opt", "no-new-privileges",         # 阻止权限提升
    "--pids-limit", "256",                         # 限制进程数量
    "--tmpfs", "/tmp:rw,nosuid,size=512m",         # 大小受限的 /tmp
    "--tmpfs", "/var/tmp:rw,noexec,nosuid,size=256m",  # 无执行的 /var/tmp
]

SETUID/SETGID 不在基础列表中 — 它们会在容器以 root 启动并且需要 init/entrypoint 降低权限(s6 权限降低路径)时按条件添加。当容器已经以非 root --user 运行时,它们会被跳过。/run tmpfs 也从基础列表中分离出来,并按镜像挂载(默认强化为 noexec,仅对从 /run 执行程序的 s6-overlay 镜像使用 exec)。

资源限制

容器资源可在 ~/.hermes/config.yaml 中配置:

yaml
terminal:
  backend: docker
  docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
  docker_forward_env: []  # 仅显式白名单;空列表将密钥排除在容器之外
  container_cpu: 1        # CPU 核心数
  container_memory: 5120  # MB(默认 5GB)
  container_disk: 51200   # MB(默认 50GB,需要 XFS 上的 overlay2)
  container_persistent: true  # 跨会话持久化文件系统

文件系统持久化

  • 持久化模式container_persistent: true):将 /workspace/root~/.hermes/sandboxes/docker/<task_id>/ 绑定挂载
  • 临时模式container_persistent: false):使用 tmpfs 作为工作区 — 清理时所有内容丢失

提示

对于生产环境网关部署,使用 dockermodaldaytona 后端将代理命令与主机系统隔离。这完全消除了危险命令审批的需要。

警告

如果您将名称添加到 terminal.docker_forward_env 中,这些变量会被有意注入到容器中供终端命令使用。这对于任务特定的凭据(如 GITHUB_TOKEN)很有用,但也意味着容器中运行的代码可以读取并泄露它们。

终端后端安全对比

后端隔离性危险命令检查最佳用途
local无 — 在主机上运行✅ 是开发、受信任的用户
ssh远程机器✅ 是在独立服务器上运行
docker容器❌ 跳过(容器是边界)生产环境网关
singularity容器❌ 跳过HPC 环境
modal云沙箱❌ 跳过可扩展的云隔离
daytona云沙箱❌ 跳过持久化云工作区

环境变量透传 {#environment-variable-passthrough}

execute_codeterminal 都会从子进程中剥离敏感环境变量,以防止 LLM 生成的代码泄露凭据。但是,声明了 required_environment_variables 的技能需要合法地访问这些变量。

工作原理

两种机制允许特定变量通过沙箱过滤器:

1. 技能作用域透传(自动)

当加载一个技能(通过 skill_view/skill 命令)并声明了 required_environment_variables 时,环境中实际设置的这些变量会自动注册为透传。缺失的变量(仍处于需要设置状态)不会注册。

yaml
## 在技能的 SKILL.md 前置元数据中
required_environment_variables:
  - name: TENOR_API_KEY
    prompt: Tenor API 密钥
    help: 从 https://developers.google.com/tenor 获取密钥

加载此技能后,TENOR_API_KEY 会透传到 execute_codeterminal(本地)以及远程后端(Docker、Modal)— 无需手动配置。

信息 — Docker 和 Modal

在 v0.5.1 之前,Docker 的 forward_env 是一个与技能透传分离的系统。现在它们已合并 — 技能声明的环境变量会自动转发到 Docker 容器和 Modal 沙箱中,无需手动添加到 docker_forward_env

2. 基于配置的透传(手动)

对于任何技能未声明的环境变量,将其添加到 config.yamlterminal.env_passthrough 中:

yaml
terminal:
  env_passthrough:
    - MY_CUSTOM_KEY
    - ANOTHER_TOKEN

凭据文件透传(OAuth 令牌等) {#credential-file-passthrough}

某些技能需要在沙箱中使用文件(而不仅仅是环境变量)— 例如,Google Workspace 将 OAuth 令牌存储为活动配置文件 HERMES_HOME 下的 google_token.json。技能在前置元数据中声明这些文件:

yaml
required_credential_files:
  - path: google_token.json
    description: Google OAuth2 令牌(由设置脚本创建)
  - path: google_client_secret.json
    description: Google OAuth2 客户端凭据

加载时,Hermes 会检查这些文件是否存在于活动配置文件的 HERMES_HOME 中,并注册以进行挂载:

  • Docker:只读绑定挂载(-v host:container:ro
  • Modal:在沙箱创建时挂载,并在每个命令前同步(处理会话中的 OAuth 设置)
  • 本地:无需操作(文件已可访问)

您也可以在 config.yaml 中手动列出凭据文件:

yaml
terminal:
  credential_files:
    - google_token.json
    - my_custom_oauth_token.json

路径相对于 ~/.hermes/。文件挂载到容器内的 /root/.hermes/。此列表由 tools/credential_files.pyterminal.credential_files)读取 — 它位于 terminal: 块下,但由凭据文件模块加载,而不是核心终端后端,因此它不是捆绑的 DEFAULT_CONFIG 快照的一部分。

每个沙箱过滤的内容

沙箱默认过滤透传覆盖
execute_code阻止名称中包含 KEYTOKENSECRETPASSWORDCREDENTIALPASSWDAUTH 的变量;仅允许安全前缀变量通过✅ 透传变量绕过两种检查
terminal(本地)阻止显式的 Hermes 基础设施变量(提供者密钥、网关令牌、工具 API 密钥)✅ 透传变量绕过阻止列表
terminal(Docker)默认无主机环境变量✅ 透传变量 + docker_forward_env 通过 -e 转发
terminal(Modal)默认无主机环境/文件✅ 凭据文件挂载;环境透传通过同步
MCP阻止除安全系统变量和显式配置的 env 之外的所有内容❌ 不受透传影响(改用 MCP env 配置)

安全考虑

  • 透传仅影响您或您的技能显式声明的变量 — 默认安全姿态对于任意 LLM 生成的代码保持不变
  • 凭据文件以只读方式挂载到 Docker 容器中
  • Skills Guard 在安装前扫描技能内容中可疑的环境访问模式
  • 缺失/未设置的变量永远不会注册(您无法泄露不存在的内容)
  • Hermes 基础设施密钥(提供者 API 密钥、网关令牌)绝不应添加到 env_passthrough 中 — 它们有专用机制

MCP 凭据处理

MCP(模型上下文协议)服务器子进程接收过滤后的环境,以防止意外凭据泄露。

安全环境变量

只有以下变量从主机透传到 MCP stdio 子进程:

PATH, HOME, USER, LANG, LC_ALL, TERM, SHELL, TMPDIR

加上任何 XDG_* 变量。所有其他环境变量(API 密钥、令牌、密钥)都被剥离

MCP 服务器 env 配置中显式定义的变量会被透传:

yaml
mcp_servers:
  github:
    command: "npx"
    args: ["-y", "@modelcontextprotocol/server-github"]
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_..."  # 仅此变量被传递

凭据编辑

MCP 工具的错误消息在返回给 LLM 之前会被清理。以下模式会被替换为 [REDACTED]

  • GitHub PAT(ghp_...
  • OpenAI 风格的密钥(sk-...
  • Bearer 令牌
  • token=key=API_KEY=password=secret= 参数

网站访问策略

您可以限制代理通过其 Web 和浏览器工具访问的网站。这对于防止代理访问内部服务、管理面板或其他敏感 URL 很有用。

yaml
## 在 ~/.hermes/config.yaml 中
security:
  website_blocklist:
    enabled: true
    domains:
      - "*.internal.company.com"
      - "admin.example.com"
    shared_files:
      - "/etc/hermes/blocked-sites.txt"

当请求被阻止的 URL 时,工具会返回一个错误,说明该域名已被策略阻止。阻止列表在 web_searchweb_extractbrowser_navigate 以及所有支持 URL 的工具中强制执行。

有关完整详情,请参阅配置指南中的网站阻止列表

SSRF 保护

所有支持 URL 的工具(Web 搜索、Web 提取、视觉、浏览器)在获取 URL 之前都会进行验证,以防止服务器端请求伪造(SSRF)攻击。被阻止的地址包括:

  • 私有网络(RFC 1918):10.0.0.0/8172.16.0.0/12192.168.0.0/16
  • 回环地址127.0.0.0/8::1
  • 链路本地169.254.0.0/16(包括云元数据 169.254.169.254
  • CGNAT / 共享地址空间(RFC 6598):100.64.0.0/10(Tailscale、WireGuard VPN)
  • 云元数据主机名metadata.google.internalmetadata.goog
  • 保留、多播和未指定地址

SSRF 保护在面向互联网的使用中始终处于活动状态,DNS 失败被视为被阻止(故障关闭)。重定向链在每个跳转处重新验证,以防止基于重定向的绕过。

有意允许私有 URL

某些设置合法地需要私有/内部 URL 访问 — 将 home.arpa 解析为 RFC 1918 空间的家庭网络、仅 LAN 的 Ollama/llama.cpp 端点、内部 wiki、云元数据调试等。对于这些情况,有一个全局退出选项:

yaml
security:
  allow_private_urls: true   # 默认:false

开启后,Web 工具、浏览器、视觉 URL 获取和网关媒体下载不再拒绝 RFC 1918 / 回环 / 链路本地 / CGNAT / 云元数据目标。这是一个有意的信任边界 — 仅在代理针对本地网络运行任意提示注入 URL 是可接受风险的机器上启用。面向公众的网关应保持关闭。

主机子字符串保护(即使底层 IP 是公共的,也会阻止类似 Unicode 域名的技巧)无论此设置如何,始终开启。

Tirith 预执行安全扫描

Hermes 集成了 tirith 用于执行前的内容级命令扫描。Tirith 可以检测模式匹配单独无法检测到的威胁:

  • 同形 URL 欺骗(国际化域名攻击)
  • 管道到解释器模式(curl | bashwget | sh
  • 终端注入攻击

Tirith 在首次使用时从 GitHub 发布版自动安装,并带有 SHA-256 校验和验证(如果 cosign 可用,则还有 cosign 来源验证)。

yaml
## 在 ~/.hermes/config.yaml 中
security:
  tirith_enabled: true       # 启用/禁用 tirith 扫描(默认:true)
  tirith_path: "tirith"      # tirith 二进制文件路径(默认:PATH 查找)
  tirith_timeout: 5          # 子进程超时秒数
  tirith_fail_open: true     # 当 tirith 不可用时允许执行(默认:true)

tirith_fail_opentrue(默认)时,如果 tirith 未安装或超时,命令将继续执行。在高安全环境中设置为 false,以在 tirith 不可用时阻止命令。

Tirith 提供预构建的 Linux(x86_64 / aarch64)和 macOS(x86_64 / arm64)二进制文件。在没有预构建二进制文件的平台(Windows 等)上,tirith 会被静默跳过 — 模式匹配保护仍然运行,CLI 不会显示“不可用”横幅。要在 Windows 上使用 tirith,请在 WSL 下运行 Hermes。

Tirith 的判定与审批流程集成:安全命令通过,而可疑和被阻止的命令会触发用户审批,并显示完整的 tirith 发现(严重性、标题、描述、更安全的替代方案)。用户可以批准或拒绝 — 默认选择是拒绝,以保持无人值守场景的安全。

上下文文件注入保护

上下文文件(AGENTS.md、.cursorrules、SOUL.md)在包含到系统提示之前会进行提示注入扫描。扫描器检查:

  • 忽略/无视先前指令的指令
  • 带有可疑关键词的隐藏 HTML 注释
  • 尝试读取密钥(.envcredentials.netrc
  • 通过 curl 泄露凭据
  • 不可见 Unicode 字符(零宽度空格、双向覆盖)

被阻止的文件会显示警告:

[已阻止:AGENTS.md 包含潜在的提示注入(prompt_injection)。内容未加载。]

生产环境部署最佳实践

网关部署清单

  1. 设置显式白名单 — 切勿在生产环境中使用 GATEWAY_ALLOW_ALL_USERS=true
  2. 使用容器后端 — 在 config.yaml 中设置 terminal.backend: docker
  3. 限制资源限制 — 设置适当的 CPU、内存和磁盘限制
  4. 安全存储密钥 — 将 API 密钥保存在 ~/.hermes/.env 中,并设置适当的文件权限
  5. 启用私信配对 — 尽可能使用配对码而不是硬编码用户 ID
  6. 审查命令白名单 — 定期审计 config.yaml 中的 command_allowlist
  7. 设置 terminal.cwd — 不要让代理从敏感目录操作
  8. 以非 root 用户运行 — 切勿以 root 用户运行网关
  9. 监控日志 — 检查 ~/.hermes/logs/ 中的未授权访问尝试
  10. 保持更新 — 定期运行 hermes update 以获取安全补丁

保护 API 密钥

bash
## 为 .env 文件设置适当的权限
chmod 600 ~/.hermes/.env
## 为不同服务保留不同的密钥
## 切勿将 .env 文件提交到版本控制

网络隔离

为了最大安全性,请在单独的机器或虚拟机上运行网关。在 config.yaml 中设置 terminal.backend: ssh,然后通过 ~/.hermes/.env 中的环境变量提供主机详细信息:

yaml
## ~/.hermes/config.yaml
terminal:
  backend: ssh
bash
## ~/.hermes/.env
TERMINAL_SSH_HOST=agent-worker.local
TERMINAL_SSH_USER=hermes
TERMINAL_SSH_KEY=~/.ssh/hermes_agent_key

SSH 连接详细信息位于 .env(而不是 config.yaml)中,因此它们不会被检入或与配置文件导出一起共享。这使网关的消息连接与代理的命令执行保持分离。

供应链建议检查

Hermes 内置了一个建议扫描器,用于标记活动 venv 中与已知受损版本(例如 2026 年 5 月的 mistralai 2.4.6 投毒事件)匹配的 Python 包。实现位于 hermes_cli/security_advisories.py

运行方式:

  • CLI 启动横幅。 如果任何建议匹配,则打印一行警告,并指向 hermes doctor 以获取完整的修复措施。
  • hermes doctor 显示每个活动建议的版本详情和 2-4 步修复说明。
  • 网关启动。 记录到 gateway.log;第一条交互消息会显示一个简短的操作员横幅。

每个建议都有一个稳定的 ID。一旦您阅读并处理了它,就可以永久忽略它:

bash
hermes doctor --ack <advisory-id>

确认信息持久化到 config.security.acked_advisories 中,并在重启后保留。旧建议有意从目录中移除 — 保留它们可以确保新安装的用户了解历史上受损的版本,这些版本可能仍缓存在私有镜像中。

检查本身仅使用标准库,每个建议执行一次 importlib.metadata.version() 查找,因此可以在每次启动时安全运行。

可选依赖的延迟安装

许多功能(Mistral TTS、ElevenLabs、Honcho 记忆、Bedrock、Slack、Matrix 等)依赖于并非每个用户都需要的 Python 包。Hermes 在首次使用时延迟安装这些包,而不是在 hermes-agent[all] 中急切安装。实现位于 tools/lazy_deps.py

这解决了以下权衡:

  • 脆弱性。 当一个额外的传递依赖在 PyPI 上不可用时(因恶意软件被隔离、被撤回、上传损坏),整个 [all] 解析会失败,新安装会静默回退到精简层级 — 同时丢失 10 多个不相关的额外功能。延迟安装将每个后端隔离,因此一个被投毒的依赖不会破坏不相关的功能。
  • 臃肿。 只与一个提供者对话的用户不再需要拉取数百个他们永远不会导入的包。

工作原理:

  1. 后端模块在其首次导入路径的顶部调用 ensure("feature.name")
  2. 如果依赖缺失,ensure 会检查 config.yaml 中的 security.allow_lazy_installs(默认 true),并为白名单中的规格运行 venv 作用域的 pip install
  3. 如果安装失败或用户禁用了延迟安装,调用会抛出 FeatureUnavailable,并附带实际的 pip stderr 和指向 hermes tools 的提示。

tools/lazy_deps.py 强制执行的安全保证:

保证含义
仅 venv 作用域安装目标为活动 venv 中的 sys.executable — 绝不会是系统 Python
仅按名称从 PyPI 安装规格接受 "package>=1.0,<2" 语法。不支持 --index-urlgit+https:// 或 file: 路径 — 恶意的 config.yaml 无法重定向安装
白名单只有出现在树内 LAZY_DEPS 映射中的规格才能通过此路径安装。功能名称中的拼写错误不会获得安装任意内容的行为
可选择退出设置 security.allow_lazy_installs: false 可完全禁用运行时安装。适用于受限网络或严格的安全策略
无静默重试失败会显示为 FeatureUnavailable — 不缓存错误状态,无重试风暴

要禁用运行时安装:

yaml
## ~/.hermes/config.yaml
security:
  allow_lazy_installs: false

禁用后,需要可选依赖的后端会告诉用户手动运行安装(pip install …)或通过 hermes tools 选择其他后端。



分享: