07 エージェントハーネスと安全装置 — AIにコマンド実行を許す前に
AIに「ファイルを書き換える」「コマンドを実行する」力を渡すとき、鍵なしで渡してはいけません。この章では、NexusCoreのエージェントハーネスがどうやって3層の防御で危険を抑えるかを解説します。
3層の防御
flowchart TB
A["🤖 AI「コマンドを実行したい」"] --> B{"🚪 第1壁: 禁止パターン"}
B -->|"rm -rf・sudo 等"| C["❌ 人間に聞く前で拒否"]
B -->|"ふつうのコマンド"| D{"👤 第2壁: 人間に聞く"}
D -->|"いいえ・返事なし"| E["🚫 実行しない"]
D -->|"はい"| F{"⏱ 第3壁: 時間と量の制限"}
F -->|"60秒超・出力過大"| G["🛑 自動停止"]
F -->|"OK"| H["✅ 実行"]
第1壁: 禁止パターン(deny_patterns)
rm -rf(全部消す)・sudo(管理者権限)・git push --force(履歴の書き換え)のような典型的に危険な命令は、人間に確認する前の段階で拒否されます。「聞けば通る」ことを最初から許さないのがポイントです。
第2壁: 人間への確認(ask)
通常の書き換え・実行は、そのたびに人間へ「いいですか?」と尋ねます。重要な設計判断が2つあります:
- 1件ずつ聞く(まとめて「全部許可」はしない)
- 聞ける環境になければ実行しない。人がいない場所(自動実行環境)では、AIは黙って諦めます。「聞けなかったから勝手に進めた」を許さないためです
実際に試したところ、確認が拒否・放置された場合、AIは「編集は適用されませんでした」と自分から正直に報告してきました。
第3壁: 時間と量の制限
実行は60秒で打ち切り、出力は末尾5,000文字だけ保持します。無限ループや大量出力でシステムが食い潰されるのを防ぐためです。エラーの根本原因は出力の末尾に現れることが多いため、保持するのは先頭ではなく末尾です。
正直な限界
この仕組みにも防げないことがあります。例えば、危険な命令を別の言い方に変換して隠す(エンコードして実行させる)ような手は、パターン照合では原理的に防げません。だからこそ、人間が見る「実行内容の全文表示」を最終防線としています。仕組みの限界を正直に書くことも、安全設計の一部だと考えています。
技術的な土台
<details><summary>▶ 技術的にどうなっているか</summary>
- ToolGate:
tool_policy.yamlを読み、道具1回ごとに個別判定(束ね承認不可)。policy不在・破損時は全拒否(fail-closed) - deny_patterns: 引数文字列への部分一致で即DENY。非list型の設定は破損扱いでdeny-all
- AskSession: select(2)によるstdin監視でタイムアウト=deny。TTY判定(stdin/stdout双方)でチャネル不在も即denyの二重防御
- 書く系道具: 原子書込(一時ファイル→os.replace)・symlink拒否・1MB上限・非UTF-8保護・editは複数マッチ時「ambiguous」で実行せず報告
- 実行道具: stdin=DEVNULL(対話待ちでハングしない)・encoding明示・タイムアウト値のクランプ[1,600]秒
- 実測: 承認経路でファイルが実際に書き換わること・拒否/タイムアウト経路で無変更であることを実プロバイダ+E2Eで検証済み
</details>