Claude Code に安全のフックを入れた。それで安心していた。
正直に言う。私は非エンジニアだ。コードは書けない。だから「危ない操作を止めてくれる」と紹介された無料のツールを入れて、それで守られた気になっていた。入れた、イコール、全部止まる。そう思い込んでいた。
だが「入れた」と「実際に止まる」は別だ。相方のClaude(この記事の技術の部分を書く方)に、既定のインストールが本当は何を止めて何を素通りさせるのかを、一つずつ終了コードで確かめてもらった。結論は、少し怖い。rm -rf / は実行の手前で止まる。だが本番データベースの DROP TABLE は、既定では素通りした。
以下、実測の記録。伝聞ではなく、手元で流して終了コードを見た一次の結果だ。
既定で入るのは「中核の8個」だけ
npx cc-safe-setup を引数なしで実行すると、~/.claude/hooks/ に入るのは中核の8個のフックだ。パッケージのカタログ(scripts.json)を直接読んで確認した。
内訳は、破壊的なコマンドを止める destructive-guard、分岐への直接の push を止める branch-guard、編集後の構文を検査する syntax-check、文脈の窓を監視する context-monitor、コメントの混入で許可リストが壊れるのを防ぐ comment-strip、読み取りの操作を自動で承認する cd-git-allow、.env の混入を止める secret-guard、セッションの死亡を知らせる api-error-alert。この8個。
ここで大事なのは、この8個に「本番データベースの全消しを止めるフック」が入っていないことだ。
destructive-guard が止めるもの、止めないもの
破壊的な操作の番人である destructive-guard の本体を読むと、止める対象はこうだ。危険なパスへの rm -rf、git reset --hard、git clean -fd、広いパターンでの find ... -delete、それに git checkout --force。ファイルとgitの破壊が中心だ(分岐への直接の push は別の番人 branch-guard が受け持つ)。
一方、SQL の DROP や TRUNCATE、条件のない DELETE は、この番人の対象外だった。だから既定のインストールだけの状態で、AIが psql -c "DROP TABLE users" を投げても、番人は素通りさせる。
危険なコマンドを実行せずに確かめる方法
どうやって「実行せずに」確かめたか。フックは標準入力でコマンドの文字列を受け取り、危ないと判断したら終了コード2で止める仕組みだ。だからコマンドを実際に走らせず、文字列として渡して、返ってくる終了コードだけを見ればいい。
# 実行はされない。文字列として hook に渡し、終了コードだけ見る
echo '{"tool_input":{"command":"rm -rf /"}}' | bash ~/.claude/hooks/destructive-guard.sh; echo "exit=$?"
# → exit=2(止まった)
echo '{"tool_input":{"command":"psql -c \"DROP TABLE users\""}}' | bash ~/.claude/hooks/destructive-guard.sh; echo "exit=$?"
# → exit=0(素通り)
rm -rf / は exit=2、DROP TABLE は exit=0。手元で流した実測がこれだった。本番を一度も触らずに、自分の環境で境界を確かめられる。
データベースの全消しまで止めるには
では DROP を止めたい時はどうするか。既定の8個ではなく、例集(800個以上ある)から名指しで足す。
npx cc-safe-setup --install-example block-database-wipe
これで DROP DATABASE や migrate:fresh、db:reset、TRUNCATE TABLE を終了コード2で止めるフックが入る。足した後にもう一度さっきの一行で流すと、今度は DROP TABLE が exit=2 に変わる。ちなみにこのフックは無料だ。穴を埋めるのに課金はいらない。
正直な限界も書いておく。足しても、TABLE を省いた素の TRUNCATE はすり抜けた。フックは文字列を見る最善努力の網であって、完全な保証ではない。だから宣言的な設定(permissions.deny)と、実行の手前のフックと、運用のルールを重ねる前提で使う。
まとめ
「安全ツールを入れた」で安心しない。「何が実際に止まるか」を終了コードで確かめる。これが今回の学びだ。
既定のインストールは、ファイルとgitの破壊には効く。だがデータベースの全消しは、例集から一つ足すまで素通りする。入れた時点で全部守られていると思い込むのが、一番危ない。
この「実際に止まるか終了コードで確かめる」やり方で、別の実際の事故——環境変数が原因でホームディレクトリが消える事故(起票 #75859)——を同じように調べたところ、中核フックにもう一つ穴が見つかった。見つけて直すまでを別の記事にまとめた:「安全フックを入れたから rm 事故は防げる」と思っていたら、ホームディレクトリへの削除が素通りした話。
- 無料の安全フック本体:
npx cc-safe-setup - この記事で使った検証は、危険なコマンドを一度も実行していない。フックに文字列を渡して終了コードを見ているだけだ。仕組みはMITで公開されているので、中身は自分で読める。
事故の型ごとに、何が起きて、設定と運用と復旧でどう止めるかをまとめた本も別に置いている。気になる人は著者の本の一覧から、価格と評価を見て選べる。