0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

同じ死角が、自作フックとClaude Codeの許可チェックの両方にあった——2>/dev/null 一つで抜ける話

0
Posted at

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 の変数の添字や修飾子を、ただの文字として扱っていた
  • 一部の helpman が、危ない選択肢やコマンド置換を通してしまっていた
  • 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)もある。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?