Claude Code を、ほぼ24時間ずっと自律で走らせている。シェルにも触れる状態なので、いちばん怖いのは、うっかり広い範囲を消してしまう事故だ。私は自作のフックで危険な削除を実行の手前で止め、Claude Code 自身の許可の仕組みでも危ない操作を止めている。二重の網のつもりだった。
先日、その網の片方に穴を見つけた。そして数日後、もう片方——Claude Code 公式の許可チェック——にも、まったく同じ形の穴があったと分かった。この記事は、自分の環境で終了コードまで確かめた実測と、その穴が公式にも存在したという事実を並べた記録だ。
自作フックが、2>/dev/null 一つで抜けた
私が配っている無料のフック集 cc-safe-setup の中核に、危険な削除を止めるフックがある。これに各コマンドを標準入力で渡して、止める(終了コード 2)か通す(0)かを実測した。危険なコマンドは一度も実行していない。使ったのは、npx cc-safe-setup で今インストールされる版(npm で配布中の 29.8.0、2026年7月時点)だ。フックは更新されうるので、挙動は検証した時点のものだと断っておく。
| コマンド | 終了コード | 結果 |
|---|---|---|
rm -rf ~ |
2 | 止める |
rm -rf ~ 2>/dev/null |
0 | 通す |
rm -rf "$HOME" 2>/dev/null; rm -f a |
0 | 通す |
一行目のとおり、ホームを消す rm -rf ~ は、ちゃんと止まる。ところが二行目、後ろに 2>/dev/null を足しただけで通ってしまう。同じ削除なのに、エラー出力を捨てる記号を一つ付けただけで、網を抜ける。三行目の形は、作り話ではない。ホームのつもりで一時ディレクトリを消そうとして、変数が本物のホームに解決され、書類や画像や設定を失った——という実際の事故の報告(GitHub の起票 #75859)が、まさにこの形だ。
なぜ抜けるのか。文字列で危険を判定する網は、「どこまでが削除の対象か」を字面で区切ろうとする。2>/dev/null は、シェルにとっては「エラー出力を捨てる」という別の指示だが、字面を追う網は、そこで区切りが狂う。シェルが実際にコマンドをどう解釈するかと、網が字面をどう区切るかが、ずれている。この一点の隙間を、リダイレクトの記号が突く。
同じ死角が、公式の許可チェックにもあった
自作の網の話だけなら、「お前のフックが雑なだけだ」で終わる。ところが、Claude Code の変更履歴の 2.1.214 を読んで、手が止まった。この版で修正された項目に、こう書いてある(要旨)。
「Bash の許可チェックを、リダイレクトの形について安全側に倒す(止める)よう修正した。bash の解釈と、許可の判定の解釈が食い違う形だ」
つまり、リダイレクトの形で、シェルの解釈と許可の網の解釈がずれて素通りする——私が自作フックで見つけたのと、まったく同じ死角が、Claude Code の公式の許可チェックにも、この版まで存在していた。
しかも 2.1.214 で修正された許可チェックの素通りは、これ一つではない。同じ版に、こう並んでいる。
- 一万文字を超える長いコマンドの判定を誤っていた(以後は必ず確認を出す)
- 二重角括弧の中の zsh の変数の添字や修飾子を、ただの文字として扱っていた
- 一部の
helpやmanが、危ない選択肢やコマンド置換を通してしまっていた - Windows のあるシェルのセッションでの許可チェックの素通り
全部、字面の判定と、シェルが実際にどう解釈するかの、ずれを突く形だ。一つの版で、この種の穴が一度に五つ修正された。字面で危険を判定する仕組みが、書き方を変えるたびに抜けられる——という構造の弱さが、公式の許可チェックにも、私のフックにも、同じように出ていた。
だからどうするか
まず、Claude Code を 2.1.214 以降に上げる。上の許可チェックの素通りは、この版で塞がれている。無料でできる、いちばん確実な一手だ。
ただし、これで安心してはいけない。一つの版で五つ塞がれたということは、字面に頼る判定が、書き方の数だけ穴を持つという証拠でもある。次の書き方で、また抜けられうる。だから、許可チェックという一枚の網だけに、取り返しのつかない操作を預けない。層で守る。
- 消す前に、目で確かめる。削除の前に、何が消えるかを先に出す癖をつける。
findなら消す動作を付けずに一覧だけ先に見る。git cleanなら空打ちで確かめてから実行する。 - 消える前提で、退避を作る。危ない操作の前に、退避のブランチを切る、コミットしておく、バックアップを取る。網が抜けても、失われるのは戻せる範囲に留まる。
- 対象を名指しで絞る。変数に頼らない。#75859 の核は、消す対象を変数(
$HOME)に任せたことだった。変数は、思っていない値に解決される。消すのが分かっているサブディレクトリなら、rm -rf ./buildのように相対の名指しで、その一つだけを対象にする。 - 設定・実行・復旧を独立させる。許可チェックや自作フックのような実行の手前の網は、多層のうちの一枚に過ぎない。設定で危ない道具の呼び出しを許可しない層、実行の手前で止める層、抜けても戻せる復旧の層を、互いに独立に重ねる。
正直に書いておくと、私の無料フック cc-safe-setup も、上の表のとおり、この 2>/dev/null の形をまだ通してしまう(単独の危険な削除は止める)。だから「これを入れれば安全」とは言わない。最も起きやすい形を止める一枚として使い、その上で層を重ねてほしい。字面に頼る一枚の網は、公式でも自作でも、書き方を変えれば抜ける。それを前提にした多層の守りだけが、あなたのデータを守る。
自律で走らせる Claude Code の事故を、実行の手前で止める設定とフックの集まりは、無料で配っている(npx cc-safe-setup)。今回のような「一枚の網の限界と、層で守る具体的な組み方」を、実際の事故の記録と一緒に体系立ててまとめた本(¥800)もある。
- 無料の設定とフック:
npx cc-safe-setup - Claude Code 事故防止ハンドブック(¥800): https://zenn.dev/yurukusa/books/6076c23b1cb18b