Claude Media
Read denyルールがあるとcd複合コマンドで承認が求められる — Claude Code

Read denyルールがあるとcd複合コマンドで承認が求められる — Claude Code

Read()のdenyルールが1つでもあると、cdを含む一部の複合コマンドはauto modeでもbypassPermissionsでも承認を求められます。v2.1.257〜261の経緯と回避策です。

permissions.denyにRead()のルールを1つでも置いていると、cdを含む複合コマンドが絶対パス指定でも承認待ちになることがあります。auto modeはもちろん、bypassPermissions(--dangerously-skip-permissions)でも同じプロンプトが出ています。複数のOSから同様の報告が上がっています。原因はRead()のdenyルールが存在するだけでルート自体が「安全側に倒して聞く」判定へ切り替わる、内部の解決ロジックにあります。Edit・Writeが止まる「Read deny rule」エラーの対処とは別のエラー経路です。cdとgitの組み合わせで出る仕様上の確認やWindows Git Bashの回帰はClaude Codeでcdに許可プロンプトが出る原因と対処法で扱っています。ここではRead()のdenyルールが引き金になる確認を扱います。

何が起きるか

この挙動はWindows(Git Bash・ネイティブ実行の両方)だけでなく、macOSとLinux(Arch、WSL2)でも再現が報告されています。特定OSに閉じた不具合ではありません。

引っかかるのは「cdのあと相対パスで何かを読む」形の複合コマンドです。次の2行は同じ処理内容なのに、結果が変わります。

cd /d/dev/myrepo && sed -n 1,2p README.md
cd /d/dev/myrepo && sed -n 1,2p README.md; echo done

cdの対象は同じ絶対パスのリテラルで、読んでいるファイルも同じです。それでも1行目は素通りし、2行目は;が付いた瞬間に確認プロンプトへ切り替わります。表示される文言は次の形です。

reads a file by a relative path after a cd in a compound command; which file that is
cannot be resolved statically while a Read() deny rule is configured, so this needs approval.

grepを含む複合コマンドでは、対象パスの誤認も報告されています。次のコマンドの実際の検索パスは.です。

cd /d/dev/myrepo && echo "=== X ==="; grep -rn "X" --include=*.cs .

それでもダイアログは--include=*.csを検索先として名指しします。区切りが増えるほど、内部のオペランド抽出は誤りやすくなります。

どんな形が引っかかるか

複合コマンドはサブコマンドごとに判定されるのが基本です(Claude CodeのBash権限ルールは複合コマンドをどう評価するか)。Read()のdenyルールが有効な状態では、cdを含む形だけが別枠で評価されます。複数の環境から報告された組み合わせを、承認の要不要でまとめると次のとおりです。

複合コマンドの形結果
cd <絶対パス> && sed -n 1,2p file結果通る
cd <絶対パス> && sed -n 1,2p file; echo done結果確認が必要
cd <絶対パス>; sed -n 1,2p file結果確認が必要
cd <絶対パス> && cat a && cat b(読み取りが複数連続)結果確認が必要
cd <相対パス>; grep -rn pat file結果確認が必要
単独のsed -n 1,2p file(cdなし)結果通る

;が入る、cdの対象が相対パス、あるいは&&チェーンの中で読み取りコマンドが複数連なる、のいずれかに当てはまると確認プロンプトに切り替わります。cdが絶対パスの単純な&&一本だけなら通るという境界線です。

サブエージェント経由だと1ファイルにつき1回の承認になる

このプロンプトはサブエージェントが実行したBash呼び出しでも発生し、親セッション側の手動承認として表示されます。組み込みのgeneral-purposeサブエージェントやPlanサブエージェントなど、種類を問わず発生します。複数のサブエージェントを並列で走らせているワークフローでは、ファイルを読むたびに親セッションへ承認が積み上がる形になり、自律実行を止める要因になります。

v2.1.257からv2.1.261までの経緯

このガードは単発の不具合ではなく、修正と副作用のやり取りの中で生まれています。

バージョン変更内容
v2.1.252変更内容該当ガードなし
v2.1.257変更内容ガードが実装済み(バイナリの文字列比較で確認)
v2.1.259変更内容Read()のdenyルールをBashの引数(オプション値・git diff/git grepのファイルオペランド・cd DIR && cat FILEの複合コマンド)にも適用する変更を追加。ここでcd複合コマンドへの確認プロンプトが表に出た
v2.1.260変更内容v2.1.259の変更をリバート。Read(./**/build/**)のようなルールがnpm run buildをあらゆるモードで拒否してしまう副作用と、cd … && grepがauto modeでも確認待ちになる副作用の両方が理由
v2.1.261変更内容リバート後も測定すると、cd複合コマンドの確認プロンプト自体は残っていた

v2.1.260のリバートで消えたのは、実は2つのうち片方のゲートだけです。

bypassPermissionsでも止まらないのは2つのゲートが重なっているため

v2.1.259は2種類の確認分岐を同じ「Read()のdenyルールが存在する」という前提条件の下に追加していました。

  • 1つ目: 「only you can approve running it anyway」という文言で終わる分岐。これはbypassImmune(バイパス不可)として登録されており、allowルールでもフックのallow判定でも解除できませんでした。v2.1.260のリバートで消えたのはこちらです
  • 2つ目: cd-compound-readという内部識別子を持つ分岐。文言は前段で示した「resolved statically」の一文です。こちらは通常のaskルールと同じ扱いで、allowルールがあれば解除できます。v2.1.261の時点でもこの分岐は残っていました

bypassPermissionsで止まる報告の多くは、この2つ目のcd-compound-read分岐に該当します。bypassPermissionsはすべてのaskを素通りするわけではありません。Read()のdenyルールの存在自体をトリガーにする判定は、モードに関係なく作動します。auto modeの分類器がaskとallowをどう振り分けているかはClaude Codeのauto mode分類器は何を止めているかにまとめています。

回避策

v2.1.283までのchangelogに、cd-compound-read分岐そのものを解消したという記載は見当たりません。いくつかの回避策が個別の環境で報告されています。

  • Read()のdenyルールを外す: 最も確実ですが、.envやsecrets/を守る仕組み自体を失います。保護をRead()のdenyルールだけに頼っている場合は代償が大きい選択です。ルールの一覧・削除は/permissionsコマンドで権限ルールとauto mode拒否を管理するから行えます
  • Bashを広くallowルールに入れる: cd-compound-read分岐は通常のaskです。Bashという広いallowルールがあれば解除されます。ただし個別のdeny・askルールをすり抜ける範囲も広がります
  • PreToolUseフックでcd+相対パス読みの形自体を拒否する: フック側で「絶対パスを使ってください」という理由を返すと、Claudeは絶対パス形式に書き直して再実行します。ユーザーへの確認は発生しません。deny・askルールはフックの判定結果より優先されるため、denyルール自体は残せます
  • 無人のヘッドレス実行では--permission-prompts noneを使う: v2.1.259で追加されたフラグです。確認が発生するはずの操作はプロンプトを出さずに自動で拒否され、auto mode自体の判定は動き続けます。CIのように応答できない環境で、プロンプト待ちのままプロセスが止まるのを避けられます
  • 絶対パス1本だけの&&チェーンにとどめる: cd <絶対パス> && sed -n 1,2p fileのような形であれば確認プロンプトの発生頻度は下げられます。ただし複合コマンドの組み立てはClaude側が決めるため、CLAUDE.mdの指示だけでこの形を確実に維持することはできません

Bashを広くallowルールに入れても、実際にRead()のdenyルールへ一致するファイルの読み取りは素通りしません。deny判定はallow・askより常に優先されるため、.envそのものを読もうとする操作は引き続き拒否されます。allowルールで解除できるのは、パスがdenyルールに一致するかどうか分からないまま確認を求めてくるcd-compound-read側のaskだけです。

公式ドキュメントの読み取り専用コマンド一覧に載っていない組み合わせ

公式ドキュメントは、cdを含む読み取り専用の複合コマンドが確認待ちになる例外を2つだけ挙げています。cdのあとに別ディレクトリでgitを実行する場合と、cdのあとのリダイレクト先が解決できない場合です。どちらも「移動先で何が起きるか具体的に特定できない」という実害に基づく例外です。一方Read()のdenyルールが存在するときにcd複合コマンドが確認待ちになる今回の組み合わせは、ルールが実際に一致するかどうかとは無関係に発生します。23本のRead()denyルールを登録していても、どれ一つ触れたファイルに一致しない環境で同じ確認が出た報告もあります。この一覧には含まれておらず、ドキュメント側の想定パターンとしては明文化されていない状態です。

よくある質問

サブエージェントを使わない単一セッションでも影響しますか

します。サブエージェント経由の増幅は影響を大きくする要因であって、原因そのものではありません。単一セッションでもRead()のdenyルールが1本あれば、cdを含む複合コマンドの形次第で確認プロンプトが出ます。

Edit()のdenyルールだけを置いていれば発生しませんか

発生しません。この分岐がトリガーとして見ているのはReadという名前、またはRead(で始まるルールの存在だけです。Edit()やBash()のdenyルールしか置いていない環境では、このcd-compound-read分岐は作動しません。

まとめ

Read()のdenyルールを1本でも置いていると、cdを含む複合コマンドは;区切りや複数読み取りの連結をきっかけに確認待ちへ切り替わります。v2.1.259で表面化しました。v2.1.260のリバートは2つあった分岐のうちbypassImmune側だけを取り除いたため、cd-compound-read側はv2.1.261でも残っていました。allowルールで解除できる通常のaskである以上、Bashの広いallowルールかPreToolUseフックが当面の回避策になります。evalで包んだコマンドがdenyルールをすり抜ける別のゲートはClaude Codeの拒否ルールをeval等ですり抜けられる問題と対策で扱っています。

この記事を共有:XはてブLinkedIn