跳到主要内容

安全性

Hermes Agent 采用纵深防御(defense-in-depth)的安全模型设计。本页涵盖所有安全边界——从命令审批到容器隔离,再到消息平台上的用户授权。

概述

该安全模型包含七个层级:

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

危险命令审批

在执行任何命令之前,Hermes 会将其与一个精心维护的危险模式列表进行比对。若匹配成功,则必须由用户显式批准。

审批模式

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

approvals:
mode: manual # manual | smart | off
timeout: 60 # seconds to wait for user response (default: 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 和网关会话中均可用。内部通过设置 HERMES_YOLO_MODE 环境变量实现,该变量在每次命令执行前被检查。

危险

YOLO 模式会禁用会话期间所有危险命令的安全检查。仅在完全信任所生成命令时使用(例如在可丢弃环境中运行经过充分测试的自动化脚本)。

审批超时

当出现危险命令提示时,用户有可配置的时间窗口进行响应。若在超时时间内未作出响应,命令将默认拒绝(关闭失败)。

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

approvals:
timeout: 60 # seconds (default: 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)SQL DELETE 无 WHERE 条件
TRUNCATE TABLESQL TRUNCATE
> /etc/覆盖系统配置
systemctl stop/disable/mask停止/禁用系统服务
kill -9 -1杀死所有进程
pkill -9强制终止进程
Fork bomb 模式Fork bomb
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 -deletefind 带有破坏性操作
cp/mv/install 写入 /etc/复制/移动文件至系统配置目录
sed -i / sed --in-place 修改 /etc/在系统配置上进行就地编辑
pkill/killall hermes/gateway防止自我终止
gateway run 携带 &/disown/nohup/setsid防止网关在服务管理器外启动
信息

容器绕过:当在 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(默认)— 阻止该命令

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

在消息平台中,代理会将危险命令详情发送至聊天,并等待用户回复:

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

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

永久允许列表

使用“always”批准的命令将保存至 ~/.hermes/config.yaml

# Permanently allowed dangerous command patterns
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:

# Platform-specific allowlists
TELEGRAM_ALLOWED_USERS=123456789,987654321
DISCORD_ALLOWED_USERS=111222333444555666
WHATSAPP_ALLOWED_USERS=15551234567
SLACK_ALLOWED_USERS=U01ABC123

# Cross-platform allowlist (checked for all platforms)
GATEWAY_ALLOWED_USERS=123456789

# Per-platform allow-all (use with caution)
DISCORD_ALLOW_ALL_USERS=true

# Global allow-all (use with extreme caution)
GATEWAY_ALLOW_ALL_USERS=true
注意

如果未配置任何允许列表,且 GATEWAY_ALLOW_ALL_USERS 未启用,则所有用户均被拒绝。网关在启动时会记录警告:

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).

私信配对系统

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

工作流程如下:

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

~/.hermes/config.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()
代码有效期1 小时过期
速率限制每用户每 10 分钟最多 1 次请求
待处理上限每平台最多 3 个待处理代码
锁定机制5 次批准失败 → 1 小时锁定
文件安全所有配对数据文件设置 chmod 0600
日志记录代码从不记录到 stdout

配对 CLI 命令:

# List pending and approved users
hermes pairing list

# Approve a pairing code
hermes pairing approve telegram ABC12DEF

# Revoke a user's access
hermes pairing revoke telegram 123456789

# Clear all pending codes
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", # Drop ALL Linux capabilities
"--cap-add", "DAC_OVERRIDE", # Root can write to bind-mounted dirs
"--cap-add", "CHOWN", # Package managers need file ownership
"--cap-add", "FOWNER", # Package managers need file ownership
"--security-opt", "no-new-privileges", # Block privilege escalation
"--pids-limit", "256", # Limit process count
"--tmpfs", "/tmp:rw,nosuid,size=512m", # Size-limited /tmp
"--tmpfs", "/var/tmp:rw,noexec,nosuid,size=256m", # No-exec /var/tmp
"--tmpfs", "/run:rw,noexec,nosuid,size=64m", # No-exec /run
]

资源限制

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

terminal:
backend: docker
docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
docker_forward_env: [] # Explicit allowlist only; empty keeps secrets out of the container
container_cpu: 1 # CPU cores
container_memory: 5120 # MB (default 5GB)
container_disk: 51200 # MB (default 50GB, requires overlay2 on XFS)
container_persistent: true # Persist filesystem across sessions

文件系统持久化

  • 持久模式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云沙箱❌ 跳过持久化的云工作区

环境变量透传

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

工作原理

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

1. 技能范围透传(自动)

当通过 skill_view/skill 命令加载一个技能,并且该技能声明了 required_environment_variables 时,环境中实际已设置的这些变量将自动注册为透传变量。尚未设置的变量(仍处于待配置状态)不会被注册。

# In a skill's SKILL.md frontmatter
required_environment_variables:
- name: TENOR_API_KEY
prompt: Tenor API key
help: Get a key from 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.yaml 中添加至 terminal.env_passthrough

terminal:
env_passthrough:
- MY_CUSTOM_KEY
- ANOTHER_TOKEN

凭据文件透传(OAuth 令牌等)

某些技能需要将文件(而不仅仅是环境变量)传入沙箱中 —— 例如,Google Workspace 会将 OAuth 令牌存储为活动配置文件的 HERMES_HOME 下的 google_token.json。技能在 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 设置)
  • 本地:无需操作(文件已可访问)

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

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

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

各沙箱的过滤规则

沙箱默认过滤规则透传覆盖
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 标准输入/输出子进程:

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

以及所有 XDG_* 变量。其他所有环境变量(API 密钥、令牌、密钥)均被剥离

在 MCP 服务器的 env 配置中显式定义的变量将被传递:

mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_..." # Only this is passed

凭据脱敏

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

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

网站访问策略

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

# In ~/.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 的工具(网络搜索、网页提取、视觉识别、浏览器)在获取内容前都会验证 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 解析失败被视为被阻止(故障关闭)。重定向链在每个跳转点都会重新验证,以防止通过重定向绕过。

Tirith 预执行安全扫描

Hermes 集成了 tirith 用于在命令执行前进行内容级扫描。Tirith 能检测模式匹配无法识别的威胁:

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

Tirith 在首次使用时会从 GitHub 发布版本自动安装,并通过 SHA-256 校验和验证(若可用 cosign,则同时进行 cosign 证明验证)。

# In ~/.hermes/config.yaml
security:
tirith_enabled: true # Enable/disable tirith scanning (default: true)
tirith_path: "tirith" # Path to tirith binary (default: PATH lookup)
tirith_timeout: 5 # Subprocess timeout in seconds
tirith_fail_open: true # Allow execution when tirith is unavailable (default: 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.]

生产部署的最佳实践

网关部署检查清单

  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 —— 避免代理在敏感目录中运行
  8. 以非 root 用户运行 —— 绝对不要以 root 身份运行网关
  9. 监控日志 —— 检查 ~/.hermes/logs/ 中是否存在未经授权的访问尝试
  10. 保持更新 —— 定期运行 hermes update 以获取安全补丁

API 密钥的安全防护

# Set proper permissions on the .env file
chmod 600 ~/.hermes/.env

# Keep separate keys for different services
# Never commit .env files to version control

网络隔离

为实现最大安全性,建议将网关部署在独立的机器或虚拟机上:

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

这可确保网关的消息连接与代理的命令执行相互隔离。