跳到主要内容

安全

Hermes Agent 采用纵深防御安全模型设计。本页面涵盖每个安全边界 — 从命令批准到容器隔离再到消息平台上的用户授权。

概述

安全模型有七层:

  1. 用户授权 — 谁可以与 agent 交谈(白名单、DM 配对)
  2. 危险命令批准 — 破坏性操作的人类参与循环
  3. 容器隔离 — 具有加固设置的 Docker/Singularity/Modal 沙箱
  4. MCP 凭证过滤 — MCP 子进程的环境变量隔离
  5. 上下文文件扫描 — 项目文件中的提示注入检测
  6. 跨会话隔离 — 会话无法访问彼此的数据或状态;cron 作业存储路径加固以防止路径遍历攻击
  7. 输入清理 — 验证终端工具后端中的工作目录参数是否在白名单中,以防止 shell 注入

危险命令批准

在执行任何命令之前,Hermes 会根据危险模式列表对其进行检查。如果找到匹配项,用户必须明确批准。

批准模式

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

approvals:
mode: manual # manual | smart | off
timeout: 60 # 等待用户响应的秒数(默认:60)
模式行为
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 命令是一个切换 — 每次使用都会翻转模式:

> /yolo
⚡ YOLO mode ON — all commands auto-approved. Use with caution.

> /yolo
⚠ YOLO mode OFF — dangerous commands will require approval.

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

危险

YOLO 模式禁用会话的所有危险命令安全检查。仅在您完全信任生成的命令时使用(例如,在可处置环境中的经过良好测试的自动化脚本)。

批准超时

当危险命令提示出现时,用户有可配置的时间来响应。如果在超时内没有给出响应,默认情况下命令被拒绝(fail-closed)。

~/.hermes/config.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递归 chown 到 root
mkfs格式化文件系统
dd if=磁盘复制
> /dev/sd写入块设备
DROP TABLE/DATABASESQL DROP
DELETE FROM(无 WHERE)无 WHERE 的 SQL DELETE
TRUNCATE TABLESQL TRUNCATE
> /etc/覆盖系统配置
systemctl stop/disable/mask停止/禁用系统服务
kill -9 -1终止所有进程
pkill -9强制终止进程
Fork bomb 模式Fork bombs
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阻止在服务管理器外部启动 gateway
信息

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

批准流程(CLI)

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

  ⚠️  DANGEROUS COMMAND: recursive delete
rm -rf /tmp/old-project

[o]nce | [s]ession | [a]lways | [d]eny

Choice [o/s/a/D]:

四个选项:

  • once — 允许此单次执行
  • session — 在会话剩余时间内允许此模式
  • always — 添加到永久白名单(保存到 config.yaml
  • deny(默认)— 阻止命令

批准流程(Gateway/消息)

在消息平台上,agent 将危险命令详情发送到聊天并等待用户回复:

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

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

永久白名单

使用"always"批准的命令保存到 ~/.hermes/config.yaml

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

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

提示

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

用户授权(Gateway)

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

授权检查顺序

_is_user_authorized() 方法按此顺序检查:

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

平台白名单

~/.hermes/.env 中将允许的用户 ID 设置为逗号分隔的值:

# 平台特定白名单
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所有用户都被拒绝。Gateway 在启动时记录警告:

No user allowlists configured. All unauthorized users will be denied.
Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access,
or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id).

DM 配对系统

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

工作原理:

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

~/.hermes/config.yaml 中控制未授权直接消息的处理方式:

unauthorized_dm_behavior: pair

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

安全功能(基于 OWASP + NIST SP 800-63-4 指导):

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

配对 CLI 命令:

# 列出待批准和已批准的用户
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):

_SECURITY_ARGS = [
"--cap-drop", "ALL", # 删除所有 Linux capabilities
"--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
"--tmpfs", "/run:rw,noexec,nosuid,size=64m", # 不可执行的 /run
]

资源限制

容器资源可在 ~/.hermes/config.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):从 ~/.hermes/sandboxes/docker/<task_id>/ 绑定挂载 /workspace/root
  • 临时模式container_persistent: false):使用 tmpfs 作为工作区 — 清理时所有内容丢失
提示

对于生产 gateway 部署,使用 dockermodaldaytona 后端将 agent 命令与主机系统隔离。这完全消除了对危险命令批准的需要。

注意

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

终端后端安全比较

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

环境变量传递

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

工作原理

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

1. Skill 范围的传递(自动)

当加载 skill(通过 skill_view/skill 命令)并声明 required_environment_variables 时,任何实际设置在环境中的变量都会自动注册为传递。未设置的变量(仍处于 setup-needed 状态)不会注册。

# 在 skill 的 SKILL.md frontmatter 中
required_environment_variables:
- name: TENOR_API_KEY
prompt: Tenor API key
help: Get a key from https://developers.google.com/tenor

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

Docker 和 Modal

在 v0.5.1 之前,Docker 的 forward_env 是独立于 skill 传递的系统。它们现在已合并 — skill 声明的 env 变量自动转发到 Docker 容器和 Modal 沙箱,无需手动将它们添加到 docker_forward_env

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

对于任何 skill 未声明的 env 变量,请将它们添加到 config.yaml 中的 terminal.env_passthrough

terminal:
env_passthrough:
- MY_CUSTOM_KEY
- ANOTHER_TOKEN

凭证文件传递(OAuth 令牌等)

某些 skills 需要文件(不仅仅是 env vars)在沙箱中 — 例如,Google Workspace 将 OAuth 令牌存储为活动配置文件 HERMES_HOME 下的 google_token.json。Skills 在 frontmatter 中声明这些:

required_credential_files:
- path: google_token.json
description: Google OAuth2 token (created by setup script)
- path: google_client_secret.json
description: Google OAuth2 client credentials

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

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

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

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

路径相对于 ~/.hermes/。文件挂载到容器内的 /root/.hermes/

每个沙箱过滤什么

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

安全注意事项

  • 传递仅影响您或您的 skills 明确声明的变量 — 任意 LLM 生成代码的默认安全态势不变
  • 凭证文件以只读方式挂载到 Docker 容器
  • Skills Guard 在安装前扫描 skill 内容中可疑的 env 访问模式
  • 未设置/未设置的变量永远不会被注册(您无法泄露不存在的内容)
  • Hermes 基础设施密钥(provider API 密钥、gateway 令牌)不应添加到 env_passthrough — 它们有专用机制

MCP 凭证处理

MCP(Model Context Protocol)服务器子进程接收过滤后的环境以防止意外的凭证泄露。

安全环境变量

仅这些变量从主机传递到 MCP stdio 子进程:

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

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

在 MCP server 的 env 配置中显式定义的变量会通过:

mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_..." # 仅此通过

凭证编辑

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

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

网站访问策略

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

# 在 ~/.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 的工具中强制执行。

请参阅配置指南中的 Website Blocklist 了解完整详情。

SSRF 保护

所有支持 URL 的工具(web search、web extract、vision、browser)在获取前验证 URL,以防止 Server-Side Request Forgery(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 故障被视为阻止(fail-closed)。重定向链在每个跃点重新验证,以防止基于重定向的绕过。

Tirith 预执行安全扫描

Hermes 集成了 tirith,用于在执行前进行内容级命令扫描。Tirith 检测模式匹配单独遗漏的威胁:

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

Tirith 在首次使用时从 GitHub releases 自动安装,并进行 SHA-256 校验和验证(如果 cosign 可用,还进行 cosign 起源验证)。

# 在 ~/.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 的裁决与批准流程集成:安全命令通过,而可疑和阻止的命令都触发用户的批准,并显示完整 tirith 结果(严重性、标题、描述、更安全的替代方案)。用户可以批准或拒绝 — 默认选择是拒绝,以保持无人值守场景的安全。

上下文文件注入保护

上下文文件(AGENTS.md、.cursorrules、SOUL.md)在包含在系统提示之前被扫描是否有提示注入。扫描器检查:

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

被阻止的文件显示警告:

[BLOCKED: AGENTS.md contained potential prompt injection (prompt_injection). Content not loaded.]

生产部署最佳实践

Gateway 部署清单

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

保护 API 密钥

# 设置 .env 文件的正确权限
chmod 600 ~/.hermes/.env

# 为不同服务保留单独的密钥
# 永远不要将 .env 文件提交到版本控制

网络隔离

为了最大安全性,在单独的机器或 VM 上运行 gateway:

terminal:
backend: ssh
ssh_host: "agent-worker.local"
ssh_user: "hermes"
ssh_key: "~/.ssh/hermes_agent_key"

这将 gateway 的消息连接与 agent 的命令执行分开。