安全性
Hermes Agent 采用纵深防御(defense-in-depth)的安全模型。本页涵盖所有安全边界——从命令审批到容器隔离,再到消息平台上的用户授权。
概述
该安全模型包含七层防护:
- 用户授权 —— 谁可以与代理通信(白名单、私信配对)
- 危险命令审批 —— 破坏性操作需人工介入确认
- 容器隔离 —— 使用 Docker/Singularity/Modal 进行沙箱化,配置强化
- MCP 凭据过滤 —— MCP 子进程的环境变量隔离
- 上下文文件扫描 —— 在项目文件中检测提示注入攻击
- 跨会话隔离 —— 各会话间无法访问彼此的数据或状态;定时任务存储路径经过加固,防止路径遍历攻击
- 输入净化 —— 终端工具后端中的工作目录参数会根据白名单进行验证,防止 shell 注入
危险命令审批
在执行任何命令前,Hermes 会将其与一个精心维护的危险模式列表进行比对。若匹配成功,则必须由用户显式批准。
审批模式
审批系统支持三种模式,通过 approvals.mode 在 ~/.hermes/config.yaml 中配置:
approvals:
mode: manual # manual | smart | off
timeout: 60 # seconds to wait for user response (default: 60)
| 模式 | 行为 |
|---|---|
| manual(默认) | 对所有危险命令始终提示用户确认 |
| smart | 使用辅助大语言模型评估风险。低风险命令(如 python -c "print('hello')")自动批准;真正危险的命令自动拒绝。不确定的情况则升级为手动提示。 |
| off | 禁用所有审批检查 —— 等同于使用 --yolo 运行。所有命令无提示直接执行。 |
将 approvals.mode: off 设置为 off 会禁用所有安全提示。仅在可信环境(CI/CD、容器等)中使用。
YOLO 模式
YOLO 模式可绕过当前会话中所有危险命令的审批提示。可通过以下三种方式激活:
- CLI 标志:使用
hermes --yolo或hermes chat --yolo启动会话 - 斜杠命令:在会话中输入
/yolo可切换开启/关闭 - 环境变量:设置
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/DATABASE | SQL DROP |
DELETE FROM(无 WHERE 子句) | 无 WHERE 条件的 SQL DELETE |
TRUNCATE TABLE | SQL TRUNCATE |
> /etc/ | 覆盖系统配置文件 |
systemctl stop/disable/mask | 停止/禁用系统服务 |
kill -9 -1 | 杀死所有进程 |
pkill -9 | 强制杀死进程 |
| 分叉炸弹模式 | 分叉炸弹(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 rm | xargs 配合 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 | 防止在服务管理器外启动网关 |
容器绕过:当在 docker、singularity、modal 或 daytona 后端运行时,危险命令检查将跳过,因为容器本身已是安全边界。容器内的破坏性命令无法影响宿主机。
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(默认)—— 拒绝该命令
网关/消息平台中的审批流程
在消息平台上,代理会将危险命令详情发送至聊天,并等待用户回复:
- 回复 yes、y、approve、ok 或 go 以批准
- 回复 no、n、deny 或 cancel 以拒绝
当运行网关时,HERMES_EXEC_ASK=1 环境变量会自动设置。
永久白名单
选择“always”批准的命令会被保存至 ~/.hermes/config.yaml:
# Permanently allowed dangerous command patterns
command_allowlist:
- rm
- systemctl
这些模式会在启动时加载,并在所有未来会话中静默通过。
使用 hermes config edit 可查看或移除永久白名单中的条目。
用户授权(网关)
运行消息网关时,Hermes 通过分层授权系统控制谁可以与机器人互动。
授权检查顺序
_is_user_authorized() 方法按以下顺序检查:
- 平台级全局允许标志(如
DISCORD_ALLOW_ALL_USERS=true) - 私信配对批准列表(通过配对码批准的用户)
- 平台特定白名单(如
TELEGRAM_ALLOWED_USERS=12345,67890) - 全局白名单(
GATEWAY_ALLOWED_USERS=12345,67890) - 全局允许所有(
GATEWAY_ALLOW_ALL_USERS=true) - 默认:拒绝
平台白名单
在 ~/.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 批准。
工作流程如下:
- 未知用户向机器人发送私信
- 机器人回复一个 8 位字符的配对码
- 机器人所有者在 CLI 上运行
hermes pairing approve <platform> <code> - 该用户将被永久批准用于该平台
在 ~/.hermes/config.yaml 中控制未授权私信的处理方式:
unauthorized_dm_behavior: pair
whatsapp:
unauthorized_dm_behavior: ignore
pair为默认设置。未经授权的私信将收到配对码回复。ignore会静默丢弃未经授权的私信。- 平台配置项会覆盖全局默认设置,因此你可以在 Telegram 上保持配对功能,同时在 WhatsApp 上保持静默。
安全特性(基于 OWASP 与 NIST SP 800-63-4 指导原则):
| 特性 | 说明 |
|---|---|
| 码格式 | 从 32 个无歧义字符组成的字母表中生成 8 位字符(不含 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 作为工作区——清理后所有内容将丢失
对于生产环境网关部署,建议使用 docker、modal 或 daytona 后端,以实现代理命令与主机系统的完全隔离。这可彻底消除危险命令审批的需求。
如果你向 terminal.docker_forward_env 添加变量,这些变量会被有意注入容器中的终端命令环境。这对任务专用凭据(如 GITHUB_TOKEN)非常有用,但也意味着容器内运行的代码可能读取并窃取这些变量。
终端后端安全对比
| 后端 | 隔离程度 | 危险命令检查 | 适用场景 |
|---|---|---|---|
| local | 无隔离 —— 在主机上运行 | ✅ 是 | 开发、可信用户 |
| ssh | 远程机器隔离 | ✅ 是 | 部署在独立服务器上 |
| docker | 容器隔离 | ❌ 跳过(容器即边界) | 生产网关 |
| singularity | 容器隔离 | ❌ 跳过 | HPC 环境 |
| modal | 云沙箱隔离 | ❌ 跳过 | 可扩展的云隔离 |
| daytona | 云沙箱隔离 | ❌ 跳过 | 持久化的云工作区 |
环境变量透传
execute_code 与 terminal 均会从子进程移除敏感环境变量,防止 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_code、terminal(本地),以及远程后端(Docker、Modal)——无需手动配置。
在 v0.5.1 之前,Docker 的 forward_env 与技能透传是两个独立系统。现在已合并——技能声明的环境变量会自动转发至 Docker 容器和 Modal 沙箱,无需手动添加至 docker_forward_env。
2. 配置驱动透传(手动设置)
对于未被任何技能声明的环境变量,可将其添加至 terminal.env_passthrough 的 config.yaml 中:
terminal:
env_passthrough:
- MY_CUSTOM_KEY
- ANOTHER_TOKEN
凭据文件透传(OAuth token 等)
某些技能需要在沙箱中访问文件(而不仅是环境变量)——例如,Google Workspace 会将 OAuth token 存储在活动配置文件的 google_token.json 下,路径为 HERMES_HOME。技能可在前端元数据中声明这些文件:
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 | 阻止名称包含 KEY、TOKEN、SECRET、PASSWORD、CREDENTIAL、PASSWD、AUTH 的变量;仅允许“安全前缀”变量通过 | ✅ 透传变量可绕过双重检查 |
| 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 服务器配置文件中显式定义的变量将被传递:
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_search、web_extract、browser_navigate 及所有支持 URL 的工具中统一强制执行。
详见配置指南中的 网站黑名单 获取完整说明。
SSRF 防护所有具备 URL 能力的工具(网页搜索、网页提取、视觉分析、浏览器)在获取数据前都会对 URL 进行验证,以防止服务器端请求伪造(SSRF)攻击。被阻止的地址包括:
- 私有网络(RFC 1918):
10.0.0.0/8,172.16.0.0/12,192.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.internal,metadata.goog - 保留地址、组播地址及未指定地址
SSRF 防护始终启用,不可关闭。DNS 解析失败将被视为访问被阻断(安全优先策略)。重定向链中的每一跳均会重新验证,防止通过重定向绕过防护。
Tirith 执行前安全扫描
Hermes 集成了 tirith 用于在命令执行前进行内容级扫描。Tirith 能检测仅靠模式匹配无法识别的威胁:
- 同形异义域名欺骗(国际化域名攻击)
- 管道注入解释器模式(
curl | bash,wget | sh) - 终端注入攻击
Tirith 在首次使用时会自动从 GitHub 发布版本安装,并通过 SHA-256 校验码验证完整性(若可用 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_open 为 true(默认值)时,若 Tirith 未安装或超时,命令仍可继续执行。在高安全性环境中,请设置为 false,以在 Tirith 不可用时阻止命令执行。
Tirith 的判断结果将集成至审批流程:安全命令直接通过;可疑或被阻止的命令将触发用户审批,并附带完整的 Tirith 分析报告(严重性、标题、描述、更安全的替代方案)。用户可选择批准或拒绝——默认选项为拒绝,以保障无人值守场景的安全性。
上下文文件注入防护
上下文文件(AGENTS.md、.cursorrules、SOUL.md)在被纳入系统提示前会经过提示注入检测。扫描内容包括:
- 指示忽略/无视先前指令的指令
- 包含可疑关键词的隐藏 HTML 注释
- 试图读取密钥的行为(
.env,credentials,.netrc) - 通过
curl实现凭证外泄 - 不可见 Unicode 字符(零宽空格、双向覆盖字符)
被拦截的文件将显示警告:
[BLOCKED: AGENTS.md contained potential prompt injection (prompt_injection). Content not loaded.]
生产环境部署最佳实践
网关部署检查清单
- 设置明确的白名单 —— 生产环境中绝不能使用
GATEWAY_ALLOW_ALL_USERS=true - 使用容器后端 —— 在 config.yaml 中设置
terminal.backend: docker - 限制资源配额 —— 设置合理的 CPU、内存和磁盘限制
- 安全存储密钥 —— 将 API 密钥存放在
~/.hermes/.env并配置正确的文件权限 - 启用 DM 配对 —— 尽可能使用配对码而非硬编码用户 ID
- 审查命令白名单 —— 定期审计 config.yaml 中的
command_allowlist - 设置
MESSAGING_CWD—— 避免代理在敏感目录中运行 - 以非 root 用户运行 —— 永远不要以 root 权限运行网关
- 监控日志 —— 检查
~/.hermes/logs/是否存在未经授权的访问尝试 - 保持更新 —— 定期运行
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"
此举可确保网关的消息连接与代理的命令执行完全隔离。