MENU

Claude Code hookは安全か?822回ブロックの落とし穴を検証

Claude CodeやCodex CLIにhookを設定して「危険なコマンドを止める」仕組みを入れたものの、それが本当に危ないコマンドを止めているのか、自信を持って言えるでしょうか。

hookのブロック回数をダッシュボードで眺めて「今日も何件も止まったから大丈夫」と安心してしまうのは、実は危うい状態かもしれません。ブロックされた回数は、守られた量を測る指標ではないからです。

この記事では、Zennで公開されている技術書『Claude Code のガードレール — hook は822回止めたのに、危険な操作は書き方を変えるだけで通っていた』(著者: くぅ氏)の内容をもとに、Claude CodeのPreToolUse hookが抱える構造的な盲点と、自分のガードレールを検証する具体的な手順を紹介します。

  • hookの「ブロック回数」がなぜ安全性の指標にならないのか
  • 本番のDDLコマンドが822回のブロックをすり抜けて素通りしていた背景
  • 自分のガードレールを棚卸しする5つの手順の概要
  • Claude Codeのhookを実際の開発フローに組み込む際の注意点
  • hookだけに頼らない、本番環境を守るための現実的なインフラ防御策
目次

Claude Code hookとは何か、なぜ「ブロック回数」では測れないのか

Claude CodeにはPreToolUse・PostToolUseといったイベントに対してシェルコマンドを紐づけられるhook機構があり、settings.jsonに登録した条件(正規表現によるコマンドマッチングなど)に一致した操作をブロックしたり、承認を要求したりできます。危険なコマンド(rm -rfDROP TABLEgit push --forceなど)を機械的に止める防波堤として、多くの開発者が導入しています。

本書の著者は、この仕組みを自分の運用環境に入れて160セッションを回した結果、hookが822回コマンドをブロックしたと報告しています。数字だけ見れば「よく効いているガードレール」に見えます。しかし著者はここで立ち止まり、ブロックされた822件の中身と、逆に「ブロックされなかった危険な操作」の両方を突き合わせて検証しました。その結果分かったのが、本番データベースへのDDL適用コマンドはこのhookを一度も通っていなかった(=一度もブロックされていなかった)という事実です。一方で、使い捨てのコンテナに対するDROPは3回止まっていました。守りたい対象(本番DB)はノーチェックで通り、守る必要が薄い対象(使い捨てコンテナ)は繰り返し止められていたわけです。

書籍『ブロックされたは安全ではない』の概要

本書はZennのBooks形式で2026年9月20日に公開された有料コンテンツで、文章量は約53,299字、価格は1,500円です(Zennの書籍ページに記載の情報、2026年9月時点)。全13チャプター構成で、Chapter 01〜03は無料公開範囲として、はじめに(822回ブロックの逸話)、「ブロックされた」は「守られた」ではないという核心的な主張、そして自分のガードレールを数える5つの手順が読めます。Chapter 04以降は有料範囲で、正規表現がコマンドの区切りを越えて誤動作するケース、同じ結果に届く別の書き方でhookをすり抜けるケース、危険度と検知の向きが逆転しているケース、書いた例外は書いた形でしか効かないという落とし穴、迂回と解決の違い、承認フローがhookに届かない問題、集計が実際に何を数えているかの検証、そして棚卸しツールの付録まで扱われています。

著者は自己紹介で「趣味で作ったツールを本番として運用しているうちに、インフラが増えていった人」「自作ジョブスケジューラ / 自宅サーバー / LLMの無人運用」を手掛けてきたと説明しており、LLMエージェントを無人運用する現場で実際に踏んだ落とし穴を書く、という立ち位置のブログ・書籍であることが分かります。

822回ブロックしても本番DDLは素通りしていた理由

Zenn書籍のページに掲載されている概要文には、著者自身の体験としてこう説明されています。「私の環境では160セッションで822回ブロックしていました。ところが、本番のデータベースへDDLを適用したコマンドは、そのhookを一度も通っていませんでした。一方で、使い捨てのコンテナに対するDROPは3回止まっています」。この一文だけでも、hook運用における重要な教訓が読み取れます。

正規表現やパターンマッチで組んだガードレールは、「書いた形」のコマンドしか検知できません。本番DDLがブロックをすり抜けていたということは、そのコマンドが登録済みの検知パターンとは違う書き方・違う経路(例えばラップされたスクリプト経由、別のクライアント経由など)で実行されていたということです。逆に使い捨てコンテナへの操作が繰り返し止められていたのは、検知パターンがたまたまそちらの書き方に強く反応する形になっていたためです。つまり「ブロック回数が多い=守れている」のではなく、「検知パターンが偶然拾いやすい操作」が繰り返しカウントされているだけ、という状態が起こり得るわけです。

自分のガードレールを数える5つの手順(本書の骨子)

本書のChapter 03(無料公開範囲)は「自分のガードレールを数える — 5つの手順」と題され、検証手順の骨子を以下の5ステップで体系化しています。①実際に守りたい操作(本番DB操作・外部公開・課金操作など)のリストアップ、②hookが記録したブロックログの全件抽出、③守りたい操作とブロック実績の突き合わせ、④「書いた形」以外のバイパス表現(エイリアス・変数展開等)に対する耐性テスト、⑤ブロック回数という集計値が何を意味しているかの言語化です。有料範囲のChapter 04〜11では、それぞれの手順で見つかる典型的な落とし穴(正規表現がコマンド区切りを越える、同じ結果に届く別の書き方、承認フローがhookに届かない等)が個別に深掘りされている構成です。

Claude Code hookを実際の開発フローに組み込む方法

Claude Codeのsettings.jsonにはPreToolUse hookとしてBashコマンドを検査するスクリプトを登録できます。例えば危険なコマンドをブロックするhookを組む場合、多くの開発者は「危険そうなキーワードを正規表現でマッチさせて拒否する」というアプローチを取ります。設定は次のような形になります。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guardrail.sh"
          }
        ]
      }
    ]
  }
}

ここで見落とされがちなのが、hookスクリプト自身が守るべき「入出力の約束事」です。Claude CodeのPreToolUse hookは、これから実行されようとしているツール呼び出しの内容を、標準入力(stdin)経由でJSON形式で受け取ります。Bashツールであれば、おおよそ次のような形のJSONが渡されます。

{
  "session_id": "abc123",
  "tool_name": "Bash",
  "tool_input": {
    "command": "DROP TABLE users;",
    "description": "本番テーブルの削除"
  }
}

hookスクリプトはこのtool_input.commandを読み取って検査し、結果は「終了ステータス(exit code)」で返します。仕様上の意味は次の通りです。

  • exit 0: 検査を通過。Claude Codeはそのままツール実行に進みます。
  • exit 2: ブロック。stderrに出力した文字列が「なぜブロックされたか」の理由としてClaude本体(モデル)にフィードバックされ、Claude側はその理由を踏まえて別のアプローチを検討したり、ユーザーに説明したりします。コマンドは実行されません。
  • その他の非ゼロ終了コード: hookスクリプト自体のエラーとして扱われ、警告は出るもののブロックとしては機能しない場合があるため、意図的にブロックしたい場合は必ずexit 2を使う必要があります。

実際にブロックされた場合、Claude Codeの対話ターミナルにはおおよそ次のような表示が出ます(環境やバージョンによって文言は多少異なります)。

● Bash(DROP TABLE users;)
  ⎿ Blocked by hook:
    guardrail.sh (PreToolUse:Bash)
    本番データベースへのDROP文はガードレールにより拒否されました。
    レビュー承認済みのマイグレーションスクリプト経由で実行してください。

guardrail.sh側の実装イメージとしては、次のように標準入力からJSONを読み、危険パターンに一致すればstderrに理由を書いてexit 2で終了する形になります。

#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')

if echo "$command" | grep -qE '\bDROP\b|\brm -rf\b'; then
  echo "危険なコマンドを検知したためブロックしました: $command" >&2
  exit 2
fi

exit 0

例えば、このように単純なパターン一致を行うと、echo "DROP TABLE users;" | psql のような標準入力を介した間接実行や、環境変数を経由した実行をすり抜けてしまいます。本書が示すように、この方式には「同じ結果に届く別の書き方」(エイリアス、変数展開、スクリプト経由の間接実行など)や「コマンドの区切りを越える正規表現」の穴が構造的に存在します。exit 2で理由を返す仕組み自体は正しく機能していても、その手前の「検知ロジック」が甘ければ、ブロックメッセージが一度も表示されないまま危険な操作が通ってしまう、というのが本書の核心的な指摘です。

実際の開発フローに組み込む際は、hookを「入れて終わり」にせず、次のような運用サイクルを回すことが重要です。まず守りたい操作を明文化し、次にhookのブロックログとエージェントの実行履歴を突き合わせて「守りたい操作が実際に検知対象になっているか」を定期的に監査します。Claude Codeのサブエージェント機能を使えば、この監査作業自体を別セッションのレビュー専用エージェントに任せ、本流のセッションを汚染せずにログの棚卸しをさせることもできます。また、hookだけに頼らず、承認プロンプト(Permission Mode)や、本番リソースへの接続情報をそもそもエージェントの実行環境に渡さない、というアクセス制御レベルでの対策を併用することも、本書が示唆する「迂回は解決ではない」という指摘への現実的な回答になります。

hookだけに頼らない — 本番環境を守るための現実的なアーキテクチャ

「正規表現ベースのhookは書き方を変えるだけで通り抜けられる」という事実を理解すると、次に浮かぶ疑問は「では実際にどうやって本番環境を守ればよいのか」でしょう。本書が繰り返し強調しているのは、文字列マッチによる検知(hook)は最後の防波堤の一枚に過ぎず、それより手前でエージェントの「実行できる範囲」自体を狭めるインフラ・権限設計を組み合わせるべきだ、という考え方です。具体的には次のような多層防御が現実的な選択肢になります。

  • コンテナ / Dev Containerによるサンドボックス実行: エージェントのBashツールをホストOS上で直接動かすのではなく、Docker等のコンテナ内、あるいはVS Code の Dev Containers のような隔離環境の中で実行させます。コンテナ内には本番データベースへの経路(ネットワーク到達性)自体を持たせないことで、hookの検知ロジックが甘くても「そもそも本番に届かない」状態を作れます。
  • 本番接続情報の権限分離: 本番DBのホスト名・認証情報(環境変数や.env)を、エージェントが動くプロセスの環境に渡さないようにします。接続情報は人間が使う踏み台サーバーやCI/CDのシークレットストアにのみ置き、エージェントのセッションからは物理的にアクセスできない構成にすることで、「書き方を変えて検知をすり抜けたコマンド」自体が実行時に接続先を見つけられず失敗します。
  • 書き込み権限を持たないリードレプリカ専用ユーザー: エージェントに本番DBへの読み取りを許可する必要がある場合でも、書き込み・DDL権限を持たないリードレプリカ用のDBユーザーを別途発行し、それだけをエージェントに割り当てます。データベース側のGRANT設定でDROP/ALTER/TRUNCATE等の権限自体を剥奪しておけば、hookをすり抜けたコマンドがDBサーバーに到達しても、DB自体がエラーで拒否します。
  • 破壊的操作は人間承認を経由する別チャネルに寄せる: マイグレーション適用など本当に必要な本番DDLは、エージェントのBashツールから直接叩かせるのではなく、レビュー済みのマイグレーションファイルをPRとしてマージし、CI/CDパイプライン側で人間承認後に実行する、という経路に一本化します。エージェントの手元には「そもそも本番DDLを打つ手段がない」状態にすることが、正規表現の穴を塞ぐより確実です。

これらは互いに排他的な選択肢ではなく、組み合わせて多層防御にすることが前提です。hookは「うっかり」を拾うには有効ですが、権限設計やネットワーク隔離のような環境レベルの防御がなければ、本書が示した「822回ブロックしても本番DDLは素通り」という事態は形を変えて何度でも起こり得ます。本書のChapter 09「承認は、hookに届かない」も、この権限分離・承認フローの設計不備を扱っている章です。

他の安全対策・監査手法との比較

hookによるコマンドブロックは数あるAIエージェント安全対策のひとつに過ぎません。代表的なアプローチを比較します。

対策 検知方式 主な弱点 本書との関係
Claude Code hook(標準機能) PreToolUseでのコマンドパターンマッチ 書いた形以外の表現をすり抜けやすい 本書が検証対象としている仕組みそのもの
本書のガードレール棚卸し手法 ブロックログと「守りたい操作」の突き合わせ 手作業での監査コストがかかる Chapter 03・13で手順とツールを解説
gitleaks等のシークレットスキャン コミット差分の静的解析 コマンド実行時点のリスクは検知対象外 hookとは別レイヤーの対策として併用が前提
Permission Mode / 承認フロー 実行前のユーザー承認 承認疲れによる形骸化のリスク 本書Chapter 09「承認は、hookに届かない」で言及
コンテナ隔離・権限分離(本記事で補足) 実行環境自体のネットワーク到達性・DB権限の制限 初期設計コストがかかる、既存システムへの後付けが手間 hookの検知漏れを構造的に無効化する多層防御の一枚

まとめ — ガードレールは「数えて」初めて安全になる

  • hookのブロック回数は「守られた量」の指標にはならない。822回ブロックしても本番DDLが一度も検知されていなかった、という逆転現象が実際に起きています
  • 正規表現ベースの検知は「書いた形」でしか効かないため、同じ結果に届く別の書き方に弱いという構造的な限界があります
  • PreToolUse hookはstdin経由のJSONを検査し、exit 0で許可・exit 2でブロックという単純な仕組みで動いています。まずはこの入出力仕様を正しく実装することが出発点です
  • ただしhookはあくまで最後の一枚。コンテナ隔離・接続情報の権限分離・リードレプリカ専用ユーザーといった環境レベルの防御を組み合わせることで、検知漏れがあっても実害に至らない構造を作れます
  • 自分のガードレールが実際に何を止め、何を通しているかを定期的に棚卸しする手順(本書Chapter 03・12・13)を持つことが、hookを入れっぱなしにしないための現実的な対策になります

Claude Codeのhook設計そのものを見直したい方、無人運用のエージェントに危険な操作をさせない運用を体系立てて学びたい方は、Zennの本書ページでChapter 01〜03の無料公開範囲を読んでみることから始めるとよいでしょう。

よくある質問(FAQ)

Claude Codeのhookとは何ですか?

Claude CodeがBashコマンドなどのツールを実行する前後(PreToolUse/PostToolUseなど)に、settings.jsonで登録したスクリプトを差し込める仕組みです。危険なコマンドのブロックや、承認要求、ログ記録などに使われます。

この本はどこで読めますか?料金はいくらですか?

Zennの書籍(Books)機能で公開されており、価格は1,500円です(2026年9月時点のZenn書籍ページの情報)。全13チャプターのうちChapter 01〜03は無料公開範囲で、続きは購入して読む形式です。

「ブロック回数が多い=安全」ではないのはなぜですか?

ブロックされた回数は、検知パターンにたまたま一致した操作の数を数えているに過ぎません。本書の実例では、本当に守りたかった本番DBへのDDL操作は一度もブロックログに現れず、守る必要が薄い使い捨てコンテナへの操作の方が繰り返しブロックされていました。回数と重要度は必ずしも一致しません。

本の内容を実践するには何が必要ですか?

Claude Code(またはCodex CLIなど同様のhook機構を持つツール)を運用しており、settings.jsonでコマンドブロック用のhookをすでに設定している、あるいはこれから設計しようとしている開発者を主な対象としています。特別な追加ツールは必須ではありませんが、自分のブロックログを確認できる環境が前提になります。

hookの正規表現はなぜ迂回されてしまうのですか?

正規表現によるコマンドマッチは「登録したパターンと文字列として一致するか」しか判定できません。コマンドの区切り文字をまたぐ書き方や、同じ結果に到達する別のコマンド表現(エイリアス・変数展開・間接実行など)には対応できないことが多く、本書のChapter 04・05でこの問題が扱われています。

Claude Code以外(Cursor、Codex CLIなど)にも応用できる内容ですか?

本書のタイトルや章立てはClaude Codeのhookを対象にしていますが、「ブロック回数を安全性の指標にしない」「守りたい操作を先に明文化してログと突き合わせる」という検証方法論自体は、他のAIエージェントCLIのガードレール設計にも応用できる考え方です。

無料で試せる部分はありますか?

はい。Chapter 01(はじめに)、Chapter 02(「ブロックされた」は「守られた」ではない)、Chapter 03(自分のガードレールを数える5つの手順)は無料公開されています。まずはこの3章で自分の環境に当てはまるかを確認できます。

本書を読む前提知識はありますか?

Claude Codeなどのエージェント型AIコーディングツールでhookやガードレールを実際に設定した経験、あるいはこれから設定しようとしている前提知識があると理解しやすい内容です。DevOps・セキュリティの実務経験があるとより深く読めます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

CAPTCHA


目次