安全性
Hermes Agent 採用縱深防禦(defense-in-depth)的安全模型設計。本頁涵蓋所有安全邊界——從命令審批到容器隔離,再到消息平臺上的用戶授權。
概述
該安全模型包含七個層級:
- 用戶授權 —— 誰可以與 Agent 通信(白名單、私信配對)
- 危險命令審批 —— 破壞性操作需人工介入
- 容器隔離 —— 使用 Docker/Singularity/Modal 進行沙箱化,配置強化
- MCP 憑據過濾 —— MCP 子進程的環境變量隔離
- 上下文文件掃描 —— 項目文件中的提示注入檢測
- 跨會話隔離 —— 會話之間無法訪問彼此的數據或狀態;定時任務存儲路徑經過加固,防止路徑遍歷攻擊
- 輸入淨化 —— 終端工具後端的工作目錄參數會根據白名單進行驗證,防止 shell 注入
危險命令審批
在執行任何命令之前,Hermes 會將其與一個精心維護的危險模式列表進行比對。若匹配成功,則必須由用戶顯式批准。
審批模式
審批系統支持三種模式,通過 ~/.hermes/config.yaml 中的 approvals.mode 配置:
approvals:
mode: manual # 手冊|聰明|離開
timeout: 60 # 等待用戶響應的秒數(默認值:60)
| 模式 | 行為 |
|---|---|
| manual(默認) | 對所有危險命令始終提示用戶確認 |
| smart | 使用輔助 LLM 評估風險。低風險命令(如 python -c "print('hello')")自動批准。真正危險的命令自動拒絕。不確定的情況升級為人工提示。 |
| off | 禁用所有審批檢查——等同於使用 --yolo 運行。所有命令無提示直接執行。 |
將 approvals.mode: 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 # 秒(默認值: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) | SQL DELETE 無 WHERE 條件 |
TRUNCATE TABLE | SQL 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 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(默認)— 阻止該命令
審批流程(網關/消息平臺)
在消息平臺中,Agent 會將危險命令詳情發送至聊天,並等待用戶回覆:
- 回覆 yes、y、approve、ok 或 go 以批准
- 回覆 no、n、deny 或 cancel 以拒絕
運行網關時,HERMES_EXEC_ASK=1 環境變量會自動設置。
永久允許列表
使用“always”批准的命令將保存至 ~/.hermes/config.yaml:
# 永久允許危險的命令模式
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:
# 特定於平臺的許可名單
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 未啟用,則所有用戶均被拒絕。網關在啟動時會記錄警告:
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 指南):
| 特性 | 說明 |
|---|---|
| 代碼格式 | 8 位字符,來自 32 位無歧義字母表(不含 0/O/1/I) |
| 隨機性 | 密碼學安全(secrets.choice()) |
| 代碼有效期 | 1 小時過期 |
| 速率限制 | 每用戶每 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", # 刪除 ALL Linux 功能
"--cap-add", "DAC_OVERRIDE", # 根目錄 可以寫入綁定安裝的目錄
"--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 # 跨 sessions 保留文件系統
文件系統持久化
- 持久模式(
container_persistent: true):將/workspace和/root綁定掛載自~/.hermes/sandboxes/docker/<task_id>/ - 臨時模式(
container_persistent: false):使用 tmpfs 作為工作區 —— 清理時所有內容將丟失
對於生產環境的網關部署,建議使用 docker、modal 或 daytona 後端,以將 Agent 命令與宿主機系統隔離。這將完全消除危險命令審批的需求。
如果你在 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 時,環境中實際已設置的這些變量將自動註冊為透傳變量。尚未設置的變量(仍處於待配置狀態)不會被註冊。
# 在 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
加載該技能後,TENOR_API_KEY 將透傳至 execute_code、terminal(本地)、以及遠程後端(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 | 阻止名稱中包含 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 服務器的 env 配置中顯式定義的變量將被傳遞:
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=參數
網站訪問策略
您可以限制 Agent 通過其網絡和瀏覽器工具可訪問的網站。這有助於防止 Agent 訪問內部服務、管理面板或其他敏感 URL。
# 在“0”中
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 能檢測模式匹配無法識別的威脅:
- 同形異義 URL 欺騙(國際化域名攻擊)
- 管道注入解釋器模式(
curl | bash、wget | sh) - 終端注入攻擊
Tirith 在首次使用時會從 GitHub 發佈版本自動安裝,並通過 SHA-256 校驗和驗證(若可用 cosign,則同時進行 cosign 證明驗證)。
# 在“0”中
security:
tirith_enabled: true # 啟用/disable tiith掃描(默認:true)
tirith_path: "tirith" # tirith 二進制文件的路徑(默認:PATH 查找)
tirith_timeout: 5 # 子進程超時(以秒為單位)
tirith_fail_open: true # 當 tiith 不可用時允許執行(默認值: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—— 避免 Agent 在敏感目錄中運行 - 以非 root 用戶運行 —— 絕對不要以 root 身份運行網關
- 監控日誌 —— 檢查
~/.hermes/logs/中是否存在未經授權的訪問嘗試 - 保持更新 —— 定期運行
hermes update以獲取安全補丁
API 密鑰的安全防護
# 對 `.env` 文件設置適當的權限
chmod 600 ~/.hermes/.env
# 為不同的服務保留單獨的密鑰
# 切勿將 `.env` 文件提交到版本控制
網絡隔離
為實現最大安全性,建議將網關部署在獨立的機器或虛擬機上:
terminal:
backend: ssh
ssh_host: "agent-worker.local"
ssh_user: "hermes"
ssh_key: "~/.ssh/hermes_agent_key"
這可確保網關的消息連接與 Agent 的命令執行相互隔離。