Hermes Agentの依存関係をOSVで監査する|130件を実機検査

安全設定を増やしても、足元の依存パッケージには既知の脆弱性も残ります。2026 年 9 月 14 日、手元の Hermes Agent をsecurity auditへ通しました。130 コンポーネントから 14 件の finding が返りました。
Found 14 known vulnerability finding(s) across 130 component(s):
私は AI エージェントの安全を、プロンプトだけでは守りません。資格情報、実行権限、依存関係を別々に検査します。今回は OSV.dev を使う依存関係の検査に絞り、通常表示、JSON、CI 向け終了コードまで実機で確かめます。
前回の拒否線から、実行コードの来歴へ進む
前回の「Hermes Agentのdenyルールでforce pushを止める」では、危険なコマンドを実行前に止めました。今回は、許可した Hermes Agent 自身が読み込む Python package、plugin、MCP server を調べます。
| 時点 | 確認できること |
|---|---|
| 前回完了時 | approvals.denyで特定のterminal commandを拒否できます |
| 今回開始時 | 実行を許したpackageに既知の脆弱性があるかは分かりません |
| 今回完了後 | OSVのfindingを人向け表示とJSONで読み、severityを終了コードへ変換できます |
すでにhermes security auditを定期実行している場合は、「JSON を機械判定へ渡す」まで飛ばせます。
なぜAIエージェントに依存関係監査が要るのか
Hermes Agent は会話するだけの program ではありません。terminal、browser、MCP、messaging gateway を通じて外部へ接続します。依存 package の弱点は、入力処理、network 通信、credential の境界へ影響する場合があります。
一方、監査結果に脆弱性 ID が出たからといって、すぐ侵害されたとは限りません。対象機能を使っているか、攻撃条件が成立するか、修正版へ更新できるかを分けて判断します。
私なら、finding を隠すより先に記録します。ただし、件数だけで危険度を決めません。同じ問題が GHSA ID と PYSEC ID の両方で現れる場合もあるためです。
用語を揃える
| 用語 | 今回の意味 |
|---|---|
| OSV | package名とversionから既知の脆弱性を検索できる公開databaseです |
| component | 監査対象になったpackageまたはserverの1単位です |
| finding | OSV照合で返った脆弱性記録です。同じ問題の別IDを含む場合があります |
| severity | low、moderate、high、criticalなどの深刻度です |
| venv | Hermes Agentが使うPython仮想環境です |
| plugin | Hermesへ機能を追加する拡張です。requirementsも監査対象になります |
| MCP server | Model Context Protocolで外部toolを提供するprocessです |
--fail-on | 指定severity以上のfindingで終了コードを非0にするoptionです |
監査範囲を先に見る
security auditは、OS 全体を調べる scanner ではありません。Hermes Agent が管理する範囲へ照準を合わせます。
┌──────────────────┐
│ hermes security │
│ audit │
└────────┬─────────┘
│ package名 + version
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────────┐ ┌──────────────┐ ┌──────────────┐
│ Hermes venv │ │ plugin deps │ │ pinned MCP │
│ installed PyPI │ │ requirements │ │ npx / uvx │
└────────┬───────┘ └──────┬───────┘ └──────┬───────┘
└────────────────┼─────────────────┘
▼
┌──────────────────┐
│ OSV.dev API │
│ finding / fixed │
│ version │
└──────────────────┘
対象外もあります。global へ入れた package、browser extension、editor extension は、この command では調べません。container image や OS package には、それぞれ別の scanner が必要です。
commandの入口を実機で確かめる
検証環境は Hermes Agent v0.21.0 です。まず、version と option を読みました。
hermes --version
hermes security audit --help
version 表示は次のとおりでした。
Hermes Agent v0.21.0 (2026.8.31) · upstream baf7ceea · local 1068df60 (+1 carried commit)
Python: 3.11.15
OpenAI SDK: 2.24.0
監査には 4 つの実用的な option がありました。
--json
--fail-on {low,moderate,high,critical}
--skip-venv
--skip-plugins
--skip-mcp
--skip-*は調査範囲を切り分ける option です。全体検査では付けません。
130コンポーネントをOSVへ照合する
通常表示は 1 command です。
hermes security audit
手元では終了コード 0 で完了し、14 finding が出ました。デフォルトの failure 境界がcriticalであり、今回の結果に critical がなかったためです。
結果の主要部分を抜粋します。
Found 14 known vulnerability finding(s) across 130 component(s):
[venv]
HIGH httpcore2==2.7.0 GHSA-7mj9-2mp8-4m2p
fixed in: 2.10.0
HIGH httpx2==2.7.0 GHSA-7mj9-2mp8-4m2p
fixed in: 2.10.0
HIGH httpx2==2.7.0 GHSA-8xx6-hgc6-gc2m
fixed in: 2.12.0
MODERATE PyNaCl==1.5.0 GHSA-mrfv-m5wm-5w6w
fixed in: 2.5.0, 1.24.0, 1.6.2
3 件が HIGH、4 件が MODERATE、7 件が UNKNOWN でした。すべてvenv由来です。表示された package はhttpcore2、httpx2、PyNaClでした。
14 という数字は 14 種類の攻撃を意味しません。今回の一覧では、GHSA と PYSEC の ID が同じ summary や fixed version を指す行を含みます。まず ID、package、version、summary を読み、重複関係を確認します。
また、出力の fixed version は更新候補の手掛かりです。個別 package だけを無理に上げる前に、Hermes Agent 側の依存制約と release を確認します。managed install なら、先にhermes update --checkで本体更新を確認する方が安全です。
JSONを機械判定へ渡す
人が読む一覧と、automation が読む値は分けます。
hermes security audit --json
実行結果の先頭は次の構造でした。秘密の値は含まれていません。
{
"total_components_scanned": 130,
"finding_count": 14,
"findings": [
{
"package": "httpcore2",
"version": "2.7.0",
"ecosystem": "PyPI",
"source": "venv",
"vuln_id": "GHSA-7mj9-2mp8-4m2p",
"severity": "HIGH",
"fixed_versions": ["2.10.0"]
}
]
}
report 保存時は、標準出力と終了コードを両方残します。
hermes security audit --json > hermes-security-audit.json
python3 -m json.tool hermes-security-audit.json > /dev/null
printf 'json_check=%s\n' "$?"
Hermes 起動時に secret source の状態を標準出力へ表示する環境では、JSON の前に status 行も入ります。今回の環境でも status は先に出ました。表示はBitwarden Secrets Manager: applied 21 secretsです。pipeline では、出力が純粋な JSON か検査します。混在する場合は Hermes の version と起動設定を確認します。parse error を finding 0 件として扱ってはいけません。
HIGH以上を終了コード1にする
デフォルトの critical 基準では、今回の HIGH finding があっても終了コード 0 でした。CI で HIGH 以上を止めるなら、境界を明示します。
hermes security audit --fail-on high
printf 'exit=%s\n' "$?"
同じ 14 finding を表示した後、実測では非 0 になりました。
exit=1
この終了コードなら、shell、cron、GitHub Actions から判定できます。ただし、導入初日にいきなり全 job を止めると修正作業まで止まることがあります。最初は report を保存し、担当者と期限を決めます。その後、解消済みの基準を CI gate へ上げます。
私なら、critical は即時停止、high は当日調査、moderate は定期更新へ載せます。実際の優先度は、利用経路と外部公開範囲も見て決めます。
scopeを切って原因を確かめる
今回の finding が venv 由来かを確かめるため、venv だけを外しました。
hermes security audit --skip-venv --json
printf 'exit=%s\n' "$?"
結果は 0 component、0 finding でした。
{"total_components_scanned": 0, "finding_count": 0, "findings": []}
exit=0
この結果は「Hermes 全体に問題がない」という意味ではありません。今回の設定には、監査可能な pinned plugin 依存と MCP component がなかったことを示します。--skip-venvを付けたまま定期実行すると、主要な 130 component を見落とします。
切り分け option は原因調査に使い、日常の基準 run は scope を省かず実行します。
findingが出た後の順序
検出後に package 名だけを見て即時削除すると、Hermes Agent を壊す恐れがあります。次の順で扱います。
vuln_idを OSV または GitHub Advisory で開きます。- affected version と fixed version を確認します。
- 対象機能を使っているか調べます。
- Hermes Agent の更新で解消するか確認します。
- 隔離、機能停止、credential 縮小などの暫定策を決めます。
- 更新後に同じ command を再実行します。
pip install -U httpx2のような直接更新は、managed venv の整合性を崩す場合があります。Hermes 本体の release と依存宣言を優先します。修正版がまだ取り込まれていない場合は、公式 issue や advisory を追います。
よくあるエラー
| 症状 | 主な原因 | 対応 |
|---|---|---|
securityにauditがありません | Hermes Agentが古い版です | hermes --versionと公式更新手順を確認します |
| OSVへの接続で失敗します | DNS、proxy、egress制限があります | network経路を確認し、0件として記録しません |
| findingがあるのにexit 0です | デフォルトの--fail-on critical未満です | CI基準を--fail-on highなどで明示します |
| JSON parse errorになります | status行などがJSONの前へ出ています | raw outputを保存し、混在行とversionを確認します |
--skip-venvで0件になりました | 最大のscan範囲を除外しています | 切り分け後はoptionなしで再実行します |
| 同じsummaryが複数あります | GHSAとPYSECなど別IDで登録されています | IDとaffected rangeを照合し、件数だけで判断しません |
| fixed versionへ上げたらHermesが動きません | managed依存を個別に変更しました | Hermes本体のupdate経路と依存制約へ戻します |
| pluginやMCPが出てきません | unpinned commandや対象外形式です | --helpと公式の監査対象を確認します |
監査を更新作業から分離する
脆弱性 scan と自動 update を同じ job にすると、検出した瞬間に実行環境が変わります。再現性が落ち、rollback も難しくなります。
私は scan を read-only で走らせ、結果を保存します。更新は別の変更として行い、version、test、再 scan をそろえます。これなら「何を見つけたか」と「何を直したか」が混ざりません。
今回の実測では、130 component から 14 finding が返り、--fail-on highは終了コード 1 でした。venv を除外すると 0 component になりました。この差により、検出元を Hermes の Python 環境へ絞れます。
AI エージェントを長く動かすなら、権限を固めた日で終わりではありません。依存関係は更新され、advisory も後から増えます。安全性は設定値ではなく、同じ検査を繰り返せる運用で保ちます。
一次情報
| 出典 | 確認した内容 |
|---|---|
| Hermes Agent Security | defense-in-depth、supply-chain advisory checking、監査範囲 |
| Hermes Agent CLI Commands | hermes security auditと各option |
| Hermes Agent公式repository | source、release、更新元 |
| OSV API | package version照合、batch query、脆弱性ID取得 |
| OSV Schema | vulnerability recordの項目とaffected range |
| GitHub Advisory Database | GHSA IDの公開advisory |
