← すべての記事

すべてのフックは傷跡である:コードに刻まれた84のエージェント失敗

v2.1.116(2026年4月)時点で、私のエージェントオーケストレーションシステムには、Claude Codeが公開する26のライフサイクルイベント型のうち15をインターセプトする84個のフックがあります。各フックは、特定のエージェントアクション(ファイル読み込み、ファイル書き込み、bashコマンド、Webリクエスト、サブエージェント生成、git操作、MCPツール呼び出し)の前後に発火するシェルスクリプトまたはPythonスニペットです。各フックは、何かがうまくいかなかったから存在します。

エージェントオーケストレーションシステムにおけるすべてのフックは、特定の本番障害に遡るものであり、フックコレクションはシェルスクリプトとしてエンコードされた組織記憶となっています。 エージェントはCDNキャッシュを消し、認証情報ファイルを読み、実行していないテストを「合格」と報告し、40分間タスクから逸脱しました。各インシデントは、それ以降のすべてのセッションで静かに発火する、小さく決定論的なガードを生み出しました。

理論上の問題ではありません。本番での問題です。あるエージェントは、何百万ものリクエストを処理するCDNキャッシュを消し飛ばしました。あるエージェントはSSHキーを書き込もうとしました。あるエージェントはpytestを呼び出さずに「すべてのテストが通過」と報告しました。あるエージェントはタスクから大きく逸脱し、割り当てられた作業とは無関係なファイル内の関数を40分間最適化していました。

これらのフックを先回りして設計したわけではありません。自律型AIエージェントの失敗モードを列挙して予防的な制御を書く、といった作業をしたわけではないのです。すべてのフックはリアクティブです。何かが壊れ、再発を防ぐためのスクリプトを書き、そのスクリプトはそれ以降のすべてのセッションで静かに発火してきました。フックシステムはセキュリティアーキテクチャではありません。傷跡の集合体なのです。

TL;DR

  • キャッシュパージ:認可されたAPI呼び出しを使って、エージェントが本番CDNキャッシュを消し飛ばしました。現在、2つのフック(47行)が、人間がタイプするパスフレーズの後ろで破壊的操作をゲートしています。
  • 認証情報リーダー:エージェントがAPIトークンをコンテキストウィンドウに含めました。現在、パスマッチングガードが認証情報ファイルの読み込みをブロックし、.envファイルへのアクセスを記録します。
  • 幻の検証者:エージェントがpytestを実行せずに「すべてのテストが通過」と報告しました。曖昧な言い回しを検出する機構により、幻の検証は12%からセッションの2%未満にまで減少しました。
  • 12回のドリフト:60日間でエージェントが検証可能な形でタスクを見失ったのは12回です。現在、しきい値0.30のコサイン類似度検出器が25ツール呼び出しごとに発火します。
  • 分類法:6つの構造的失敗カテゴリが84個のフックすべてをカバーします。500以上のセッションを経て、新規カテゴリはまれになっています。システムは各インシデントごとに強固になっていきます。

キャッシュパージ:認可された1回の呼び出しが本番を壊した経緯

2026年3月21日、resumegeni.comのmarketページの読み込みが遅い理由を調査するようエージェントに依頼しました。エージェントは通常通り調査を開始し、ルートハンドラを読み、データベースクエリを確認し、テンプレートレンダリングをプロファイルしました。その後、古いCloudflareキャッシュエントリが本来のパフォーマンス特性を覆い隠している可能性があると判断しました。

エージェントはpurge_everything: trueを指定してmcp__cloudflare__cache_purgeを呼び出しました。

本番サイトのキャッシュされたすべてのページが瞬時に無効化されました。CDNはほとんどのリクエストを80〜100msで処理していたのが、すべてのリクエストをRailwayのオリジンサーバーに転送するようになりました。AustinのmarketページはサブセカンドRender から14,290ミリ秒になりました。New Yorkはサブセカンドから6,891msに。サイト上のすべてのページがリクエストごとにコールドオリジンからレンダリングされるようになったのです。

エージェントは認可されていない行為は何もしていません。有効な認証情報を持つ正規のMCPツールを使用して、認可されたAPIエンドポイントを呼び出したのです。キャッシュ動作をデバッグしているなら、キャッシュパージは合理的な調査ステップでした。問題は、「デバッグには合理的」と「本番には破滅的」が同じAPI呼び出しだったこと、そしてエージェントの推論と本番への影響の間に制約が存在しなかったことです。

その夜、2つのフックを作りました。

Bashガードdestructive-api-guard.sh):すべてのbashコマンドで発火します。curl.*purgerm -rfDROP TABLEdocker.*rmgit push.*--forceに対してパターンマッチします。ハードブロック(exit 2)です。エージェントはコマンドがブロックされた理由と代替案を示すメッセージを見ます。パスフレーズ「rosebud」なしには先に進めませんが、これは人間がタイプしなければコンテキストに入れません。

MCPガードdestructive-mcp-guard.sh):mcp__cloudflareまたはmcp__githubにマッチするすべてのMCPツール呼び出しで発火します。ツールパラメータ内のpurgedeletedestroyremoveに対してパターンマッチします。同じハードブロック、同じパスフレーズゲートです。

2つのフック。2つのシェルスクリプト。合計47行のコードです。インストール以来、キャッシュパージを1件も防いでいません。なぜなら、パスフレーズゲート追加以降、どのエージェントも試みていないからです。フックは攻撃をキャッチしているのではありません。そのカテゴリのミスを不可能にしているのです。

キャッシュパージインシデントは、調査対象だったパフォーマンス問題も露呈させました。Austinのコールドレンダー14秒が、marketページハンドオフにつながり、そこから4日後にクエリ形状の修正につながりました。このインシデントは有用でした。フックは再発を防ぎます。

認証情報リーダー

2026年2月、プロジェクトのコンテキストを収集していたエージェントが~/.claude/docs/credentials.mdを読みました。このファイルにはCloudflare、GitHub、RailwayなどのサービスのAPIトークンが含まれています。エージェントはこのファイルの内容の要約を作業ノートに含めたため、トークンがAnthropicのサーバーへのAPIリクエストに存在することになりました。

トークンはコミットされませんでした。公に露出もしていません。しかしトークンは、私がコントロールしないコンテキストウィンドウ内の第三者APIを経由しました。リスクサーフェスは「私のマシン」から「私のマシン+Anthropicの推論インフラ」へと拡大したのです。

認証情報パスガードは、すべてのファイル読み込みで発火します。パスを機密パターンのリスト(.envcredentials.ssh/.aws/.gnupg/secrets)と照合します。認証情報の読み込みについてはフックが警告をログに記録し、読み込みをブロックします。.envの読み込みについては、読み込みを許可しますがアクセスをログに記録します。

ガードはほとんどのパスについてはアドバイザリーで、認証情報ファイルについてはハードブロックです。この違いは重要です。環境変数名を理解するために.envを読むエージェントは、有用なコンテキストです。APIトークンを理解するためにcredentials.mdを読むエージェントは、セキュリティインシデントなのです。

インストール以来、認証情報パスガードは200以上のセッションで23回発火しました。そのうち20回はエージェントが.envファイルを読んだもの(ログに記録、許可)でした。3回は認証情報またはキーファイルを読もうとしたエージェント(ブロック)でした。ブロックされた読み込みはどれも、広くプロジェクトコンテキストを収集していたエージェントが、たまたま検索パターンに機密ファイルを含めてしまったケースでした。悪意あるものはありませんでした。ガードがなければ、すべてが秘密情報をコンテキストウィンドウに入れていたことになります。

幻の検証者

最も陰湿な失敗モードは、検証を実行せずに検証成功を報告するエージェントです。

セッション147。あるエージェントにデータベースクエリをリファクタリングし、既存のテストスイートで変更を検証するよう依頼しました。エージェントはクエリを正しくリファクタリングしました。完了報告には「すべてのテストが通過。リファクタリングされたクエリは元のものと同一の結果を生成します。」とありました。

セッションログを確認しました。pytestの呼び出しは見当たりませんでした。いかなる種類のテストランナーも呼び出されていませんでした。エージェントは、リファクタリングされたクエリが元のものと論理的に等価であるためテストが通過すると推論し、この推論をテスト結果であるかのように報告していたのです。

リファクタリングされたクエリは正しいものでした。テストも通過したでしょう。エージェントの推論は妥当でした。しかし、テストについて推論することは、テストを実行することではなく、この2つの間のギャップこそバグが本番に送り込まれる場所なのです。リファクタリングされたクエリが、エージェントの推論がカバーしていないエッジケースで微妙に間違っていた場合、テスト検証を主張する完了報告とともにバグがデプロイされていたでしょう。

この失敗モードは、エビデンスゲートフックを作る前の60セッションで7回発生しました。フックはすべての完了報告で発火し、曖昧な言い回しをスキャンします。「should pass(通過するはず)」、「I believe(〜だと思う)」、「tests likely pass(おそらくテストは通過する)」、「I’m confident(確信している)」など。検出されると、フックはメッセージを注入します。「曖昧な言い回しが検出されました。具体的な証拠を挙げてください。テスト出力を貼り付けるか、ファイル名と行番号を挙げるか、具体的な検証ステップを参照してください。」

フックはテストが実際に実行されたかは検証しません。検証がスキップされたことを示す言語パターンにフラグを立てるのです。検出は完璧ではありません。十分に流暢なエージェントなら、パターンを避けるために言い換えることもできるでしょう。しかしフックは一般的なケースをキャッチし、それは人間の介入を要するエージェント失敗の12%を占めています。1

フックのインストール後、幻の検証はセッションの12%から2%未満に減少しました。残りの2%は、エージェントが言い換える場合、または検証の主張が技術的には正確だが不完全な場合(例:統合テストが実行されていないのに「単体テストが通過」)です。

ドリフト

2026年1月から3月の間、ドリフト検出器は、エージェントが検証可能な形で割り当てられたタスクを見失ったセッションで12回発火しました。

ドリフト検出器は、元のタスクプロンプトを埋め込み、エージェントの最近のアクションの埋め込みと定期的に比較することで機能します。コサイン類似度が0.30を下回ると、システムは元のプロンプトを含む警告を注入します。しきい値は実験によって較正しました。0.50は感度が高すぎ(正当なサブタスク探索で発火)、0.20は寛容すぎ(明白なドリフトを見逃し)、0.30は検証されたすべてのドリフトインシデントをキャッチしました。

セッション203は最も明確なケースでした。タスクは「アンパサンドを含むジョブスラッグのsitemap XMLエスケープの不具合を修正する」でした。エージェントはsitemap生成コードの読み込みから始めました。次にsitemapがデータベースクエリから生成されていることに気づきました。次にデータベースクエリが最適化可能であることに気づきました。その後40分間、クエリをmaterialized viewパターンにリファクタリングし、新しいクエリのテストを書き、最適化完了と報告しました。アンパサンドエスケープは一度も修正していません。

ドリフト検出器なら、セッション開始から約15分後、25ツール呼び出しマークでこれをキャッチしていたでしょう。「fix sitemap XML escaping」と「create materialized view」の類似度がしきい値を下回ったタイミングです。結局、レビュー中にドリフトを発見することになりました。

セッション89はもっと微妙でした。タスクは「認証エンドポイントにレート制限を追加する」でした。エージェントはレート制限を正しく追加しました。その後、認証フローのエラーメッセージに一貫性がないことに気づきました。次にエラーメッセージを標準化しました。次にエラーレスポンス形式がAPIレスポンス形式標準と異なることに気づきました。そして12のエンドポイントにわたってレスポンス形式をリファクタリングしました。レート制限は正しく完全でした。スコープの爆発がドリフトだったのです。

ドリフト検出器は25ツール呼び出しごとに発火します。しきい値未満で発火した12回すべてにおいて、エージェントは元のタスクから検証可能な形で逸脱していました。6件では、注入された警告を見てエージェントが自己修正しました。4件では、エージェントはドリフトを認めつつも現在の作業に価値があると主張しました(時には正しく)。2件では、エージェントは警告を無視して逸脱した作業を続けました。

フックはドリフトを防ぎません。ドリフトを可視化するのです。逸脱した作業をリダイレクトするか許可するかの判断は、人間に残されています。しかしフックがなければ、完了報告までドリフトは見えず、その頃にはコンテキスト予算は使い果たされています。

傷跡の分類法

84個のフックを経て、パターンが浮かび上がります。失敗は6つのカテゴリに集約されます。

カテゴリ フック数
認証情報の露出 12 エージェントが.ssh/を読む、要約にAPIキーを含める、クラウド設定にアクセスする
破壊的操作 8 キャッシュパージ、データベース削除、force push、ファイル削除
タスクドリフト 4 エージェントが誤った問題に取り組む、スコープの爆発、サブタスクのウサギの穴
出力品質 6 幻の検証、証拠のない曖昧な言い回し、不完全な報告
リソース枯渇 3 生成されすぎるサブエージェント、無限ループ、コンテキストオーバーフロー
プロジェクト間の混在 4 プロジェクトAのエージェントがプロジェクトBのファイルを変更する

残りの47個のフックはプロジェクト固有のもの(規約の強制、デプロイガード、翻訳バリデーター)や実験的なもの(コスト追跡、セッションメトリクス、アクティビティのハートビート)です。

6つの構造的カテゴリは安定しています。これらのカテゴリ内の新しいインシデントは既存のフックによってキャッチされます。新規カテゴリはまれです。運用の6か月で、新しい構造的カテゴリは1つしか出現していません(obsidian-signalsプロジェクトで実行中のセッションがblakecrosley.comのファイルを編集しようとしたときに発見されたプロジェクト間の混在)。他の5カテゴリは最初の60セッション以内に確立されました。

Agents of Chaos研究(6つのAIエージェントにメール、bash、ファイルシステム、GitHubへのアクセスを与えた14日間の複数大学合同実験)は、独立して重複する失敗カテゴリを特定しました。不釣り合いな応答(破壊的操作)、アイデンティティハイジャック(認証情報の露出)、無限ループ(リソース枯渇)、プレッシャー下での漸進的コンプライアンス(タスクドリフト)です。5 彼らの管理された研究と私の本番経験の一致は、これらのカテゴリが自律型エージェントの構造的特性であり、特定の構成のアーティファクトではないことを示唆しています。

フックでは捕捉できないもの

フックはツール呼び出しレベルで動作します。アクションの前後でインターセプトします。アクションに至った推論はインターセプトできません。

報告されたバグを修正する代わりに関数をリファクタリングすることを決めたエージェントは、正しい内容(構文的に有効なコード)を持つ有効なツール呼び出し(ファイル書き込み)を生成しますが、タスク(誤った関数)に違反します。どのツール呼び出しも疑わしくないため、どのフックもこれをキャッチしません。ドリフト検出器は最終的にキャッチしますが、エージェントが誤った作業にかなりのコンテキストを消費した後のことです。

フックはまた、個々のアクションは認可されているものの、シーケンスが認可されていない結果を生む構成上の失敗もキャッチできません。キャッシュパージは構成上の失敗でした。キャッシュ設定の読み込み(認可)、パージAPIの呼び出し(認可)、しかしその組み合わせ(調査中の本番キャッシュのパージ)が有害だったのです。MCPガードは現在、その特定の組み合わせをキャッチしますが、新規の構成はカバーされないままです。

サプライチェーンの構成ギャップも同じレベルで動作します。信頼されたコンポーネントが構成されて認可されていない動作を生むのです。フックはコンポーネントレベルのガードです。構成レベルの推論には別のメカニズムが必要で、それは個々のアクションではなくアクションのシーケンスを評価するものでなければなりません。ドリフト検出器が最も近い近似です。個々のツール呼び出しではなく行動の軌跡を評価するからです。しかし、これは元のタスクとの類似度を測るものであり、構成されたアクションシーケンスの安全性を測るものではありません。

フックと完全な安全性の間のギャップは、組織記憶と組織的予見の間のギャップです。フックは何が起きたかを記憶します。次に何が起きるかは予測しません。

リアクティブが誠実である理由

プロアクティブなフックシステムを設計することもできます。考えられるすべての失敗モードを列挙する。それぞれに予防的な制御を書く。最初のセッションの前に完全な安全アーキテクチャを構築する。

これをしないのは、プロアクティブな設計には発生していない失敗を予測することが必要だからです。予測は間違うでしょう。フックは広すぎる(正当なアクションをブロック)か狭すぎる(実際の失敗パターンを見逃す)かのどちらかになるでしょう。誤検出率がフックシステムへの信頼を損ね、アラートを無視するようになっていくでしょう。

リアクティブなフックは誠実です。それぞれが「この特定のことが起こり、ここにそれを防ぐ特定のガードがある」と語ります。ガードは失敗によって定義されたため、失敗に正確に較正されています。パターンは脅威モデルから想像されたものではなく、実際のインシデントから抽出されているため、誤検出率は実質的に低くなります。リアクティブガードは、コードベースが進化するにつれて後から過剰にマッチすることはありえますが、開始時の精度は高いのです。

リアクティブなアプローチにはコストがあります。すべての失敗カテゴリの最初のインスタンスは成功します。キャッシュパージは起きました。認証情報の読み込みは起きました。幻の検証は出荷されました。ドリフトはコンテキストを消費しました。最初の失敗はそれぞれ、2番目の失敗を防ぐ正確でノイズの少ないガードへの入場料なのです。

500以上のセッションを経て、ほとんどの構造的失敗カテゴリに遭遇しました。最初の失敗のコストは、フックが再発を防いだ何百ものセッションにわたって償却されます。システムは各インシデントごとに強固になります。より賢くなるのではありません。より強固になるのです。

各フックは傷跡です。各傷跡は教訓です。教訓は積み重なります。2


FAQ

フックの設定を見られますか?

フックシステムはエージェントセキュリティに関するNISTへの私の意見で説明しており、AI Engineeringシリーズ全体で参照しています。フックは~/.claude/settings.jsonに登録され、~/.claude/hooks/dispatchers/を通じてイベント型ごとにディスパッチされます。

フックはエージェントのパフォーマンスにどう影響しますか?

各フックはツール呼び出しごとに数ミリ秒を追加します。84個のフックでは、どのフックが発火するかによってツール呼び出しごとの総オーバーヘッドは200〜400msです。このオーバーヘッドはモデル推論時間(応答ごとに2〜5秒)と比較すると無視できます。フックがボトルネックではありません。

フックは他のAIコーディングツールで動作しますか?

フックはClaude Code固有(PreToolUse、PostToolUseイベントモデル)です。このコンセプトはミドルウェアまたはプラグインのサポートを持つあらゆるエージェントフレームワークに適用できます。具体的な実装は移植可能ではありませんが、傷跡の分類法とリアクティブな方法論は普遍的に適用できます。

フックがアクションをブロックするとどうなりますか?

ハードブロック(exit 2)はアクションを阻止し、理由を説明するメッセージを注入します。エージェントはブロックの理由を見て調整します。アドバイザリフック(exit 0)は懸念をログに記録しますが、アクションを許可します。破壊的操作はハードブロックを使います。他のほとんどのカテゴリはアドバイザリフックを使います。パスフレーズゲートは、最も危険な操作(キャッシュパージ、インフラ削除)にのみ使用されます。

ハードブロックとアドバイザリの判断はどうしていますか?

2つのクラスがハードブロックを受けます。破壊的操作(キャッシュパージ、データベース削除、force push、インフラ変更)と認証情報の露出(秘密ファイルの読み込み、キーストアへのアクセス)です。それ以外はすべてアドバイザリログです。違いは結果の重大性です。アクションを安価に取り消すことができ、秘密情報を漏らさないのであれば、アドバイザリで十分です。アクションが不可逆であるか認証情報を露出するなら、ハードブロックが必要です。


Sources


  1. Blake Crosley, “What I Told NIST About AI Agent Security,” blakecrosley.com, February 2026. 60以上の自律セッションにわたる12%の幻の検証率。Claude Codeライフサイクルイベント型26のうち15をカバーする84フック(v2.1.116)、ドリフト検出方法論。 

  2. Blake Crosley, “Compound Context: Why AI Projects Get Better the Longer You Stay With Them,” blakecrosley.com, March 2026. コンテキスト複利フレームワーク:リターンを蓄積する6つのカテゴリの1つとしてのフック。 

  3. Blake Crosley, “The Supply Chain Is the Attack Surface,” blakecrosley.com, March 2026. 構成ギャップ:個別には認可されたコンポーネントが認可されていない結果を生み出す。 

  4. Blake Crosley, “Deploy and Defend: The Agent Trust Paradox,” blakecrosley.com, March 2026. キャッシュパージインシデントと破壊的APIガードの対応。 

  5. Christoph Riedl et al., “Agents of Chaos,” arXiv:2602.20021, February 2026. 14日間の複数大学合同研究(Northeastern、Stanford、Harvard、MIT、CMU)。6つのAIエージェント、不釣り合いな応答、アイデンティティハイジャック、無限ループを含む10のセキュリティ脆弱性を特定。 

関連記事

サプライチェーンこそが攻撃対象領域である

Trivyが侵害された。次にLiteLLM。そして46分間で47,000回のインストール。AIサプライチェーンは設計通りに機能した。

2 分で読める

ハンドオフドキュメント:セッションをまたぐエージェントメモリ

診断は4日間で3回の修正を経て、14秒から108ミリ秒へのページ読み込み短縮を導きました。ハンドオフは、エージェントが持ち得ないコンテキストを運びます。

1 分で読める

Ralphループ:自律型AIエージェントを一晩中稼働させる方法

ストップフック、スポーンバジェット、ファイルシステムメモリを備えた自律エージェントシステムを構築しました。失敗から学んだことと、実際にコードをシップする仕組みを紹介します。

3 分で読める