18
16

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 は eval を止めた。守っていたのは別の仕組みだった

18
Last updated at Posted at 2026-09-16

Claude Code 2.1.273(2026-09-15)の changelog に、こう書かれています。

Reverted a 2.1.268 change that checked Read and Edit deny rules on Bash lines the permission
checker can't analyze (eval, env -C); commands like time -p make build prompt again
instead of being denied

「解析できない Bash 行にも拒否ルールを当てる」という強化を戻したと読めます。
前回 tee の穴を測った続きとして、
Claude Code 2.1.268 / 2.1.271 / 2.1.273 の3つで測りました。

3バージョン × 4コマンド × 4通りの権限設定 = 120回

拒否ルールを消しても  結果は変わらなかった
止めていたのは、その手前の静的解析だった
バイパスにすると  eval で拒否ファイルに3回中3回書けた
バージョンによる差    1つも出なかった

検証環境: Windows 10 / Claude Code 2.1.268・2.1.271・2.1.273 を隔離導入 / claude -p / 測定は 2026-09-16


測り方

捨てディレクトリに、拒否ルールだけを置きます。

{
  "permissions": {
    "deny": ["Read(./secret.txt)", "Edit(./secret.txt)", "Write(./secret.txt)"]
  }
}

changelog が名指しした形を、そのままコマンドにしました。

コマンド ねらい
A eval 'echo EVAL-WROTE > secret.txt' changelog の「解析できない行」
B env -C . sh -c 'echo ENVC-WROTE > secret.txt' 同上
C time -p cp normal.txt copied.txt changelog の誤検知の例。拒否ファイルに触らない
D echo DIRECT-WROTE > secret.txt 対照。解析できる書き込み

判定はファイルの中身が変わったかだけです。自己申告は使いません。
親プロセスから CLAUDE_* が12個渡るので、毎回剥がしてから走らせます
(前回これを忘れて24回ぶん捨てました)。


結果: 3つのバージョンで、1つも違わなかった

まず既定のモードで、各3回。

コマンド Claude Code 2.1.268 2.1.271 2.1.273 止めた理由
A eval 0/3 実行 0/3 0/3 'eval' evaluates arguments as shell code
B env -C 0/3 実行 0/3 0/3 env with -C flag cannot be statically analyzed
C time -p 0/3 実行 0/3 0/3 Command appears to be an incomplete fragment
D 直接 0/3 実行 0/3 0/3 拒否ルール

理由の文字列まで同じです。 差し戻したはずの 2.1.273 でも変わりません。

一度だけ 2.1.273 で This command requires approval が増えましたが、
ログを見るとモデルが bash -c '...' で再試行した別コマンドに対する応答でした。バージョンの差ではありません。


拒否ルールを1行も書かなくても、結果は同じだった

deny丸ごと消して同じ4つを流します。ここが一番意外でした。

設定 A eval B env -C C time -p
拒否ルールあり 止まる 止まる 止まる
拒否ルールなし 止まる 止まる 止まる

拒否ルールは、これらを止めていませんでした。
止めていたのは、その手前にある Bash の静的解析です。3つとも変わっていません。

changelog の変更は、この図の2段目です。 ところが1段目で全部止まるので、
2段目まで届きません。だから差が見えませんでした。


バイパスモードにすると、eval だけ素通りした

--dangerously-skip-permissions を付けると、1段目の関門が消えます。各3回。

コマンド Claude Code 2.1.268 2.1.271 2.1.273
A eval 3/3 書き込み成功 3/3 3/3
B env -C 3/3 書き込み成功 3/3 3/3
C time -p 3/3 実行 3/3 3/3
D 直接 0/3(拒否) 0/3 0/3

D だけが止まります。 バイパスモードでも拒否ルールは生きていて、解析できる書き込みは拒否されます。

しかし eval で包むと、同じファイルに3つとも書けました。
拒否ルールが守っているのは、静的に解析できるパスだけでした。


なぜ差が見えないのか

changelog の差は「拒否される」か「確認を求められる」かです。
claude -p には答える人がいません。先ほどの requires approval も、実行されずに終わっています。

見分けるには、対話セッションでプロンプトが出るかを見るしかありません。


言えないこと

  • 差し戻しが無かったとは言えません。 言えるのは「claude -p からは見えなかった」まで
  • 対話セッションでは未検証。 time -p make build に確認が出るかは未確認です
  • 測ったのは Claude Code 2.1.268 / 2.1.271 / 2.1.273 の3点だけ。間の3つは飛ばしています
  • 拒否ルールを消した群は各1回(他は各3回)。回数が足りません
  • Windows 10 の Git Bash 環境。env -C の扱いは OS で変わる可能性があります
  • 拒否ルールを消した対照では、D だけサンドボックスが止めましたOutput redirection to ... was blocked)。D の比較はその分濁ります

まとめ

  • Claude Code 2.1.273 の差し戻しは、120回走らせても1つも観測できなかった
  • evalenv -C を止めているのは拒否ルールではない。 拒否ルールを全部消しても止まる
  • 止めているのは、その手前の静的解析。 3つとも同じ文言で止まる
  • --dangerously-skip-permissions を付けると、その関門が消える。
    解析できる書き込みは拒否されるが、eval で包むと3つとも書けた
  • claude -p では「拒否」と「確認待ち」が同じ形になる。 見分けるには対話セッションが要る

拒否ルールに Edit(./secret.txt) と書いたから守られている、とは限りません。
実際に止めているのが何なのかは、拒否ルールを消して同じことをやると分かります。


参考

関連記事


JQITのエンジニアの95%以上は未経験からの採用です。
よければコーポレートサイトにも遊びに来てください。

コーポレートサイト

エンジニア採用も行っています。もしご興味あれば覗いてみてください。

採用サイト

18
16
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
18
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?