Claude Codeで急にgrepが承認待ちになる v2.1.259でRead denyルールがBashのgrepにも効くようになった
Claude Code を bypassPermissions で走らせているのに、今日から grep -r が承認待ちで止まるようになった。原因は 2026年9月2日リリースの v2.1.259 で、settings.json の Read deny ルールが Bash の grep にも当たるようになったこと。前日の v2.1.258 と並べて実測し、通る書き方と通らない書き方を表にまとめました。
こんにちは!
昨日まで何も言わずに走っていた Claude Code の grep が、今朝(2026/9/3)から止まるようになりました。
grep on '.' would read 'C:\path\to\project\.env', which the deny rule
Read(./.env) covers; only you can approve running it anyway.grep on '-r' after a cd would search a directory that cannot be determined
here, and a Read() deny rule is configured; only you can approve running it
anyway.筆者の環境は Windows 11 で、権限モードは bypassPermissions。設定ファイルは一切触っていません。
先に結論を書いておくと、これはバグではなく
2026年9月2日リリースの Claude Code v2.1.259 に入った意図的な変更
です。
settings.json に Read(./.env) のような deny ルールがあり、Bash の grep -r の検索範囲にその deny 対象が含まれていると、「そのファイルを読みうる」と判定されて承認待ちになります。
bypassPermissions では回避できません。
この記事では、公式チェンジログと公式ドキュメントで原因を突き止めたうえで、前日の v2.1.258 と当日の v2.1.259 を手元で並べて確認し、どの書き方が通ってどの書き方が止まるのかを表にします。
当ブログでは Claude Code で正規の運用作業が「Usage Policy 違反」になる理由 や Claude Code で「court」って何? など、Claude Code の「急に挙動が変わった」系のトラブルを追いかけてきました。
今回もその一本です。
1. 原因は v2.1.259 のチェンジログに書いてある
公式チェンジログの v2.1.259(September 2, 2026)に、そのままの記述があります。
Fixed BashRead()/Edit()deny rules not covering files given as option values (--ignore-revs-file=.env,-f.env,@file),git diff/git grepfile operands, orcd DIR && cat FILEcompounds;grep -r/cp -rover a directory holding a denied file now asks
冒頭の 2 つのメッセージは、この 1 行に対応しています。
grep -r pattern . は「deny 対象ファイルを含むディレクトリに対する grep -r は確認を求める(now asks)」そのものです。
cd ... && grep -r は「cd DIR && cat FILE 複合コマンド」への対応の副作用とみられます。cd 後のカレントディレクトリを Claude Code が静的に確定できないので、安全側に倒して確認になる、という読みです(推測を含みます)。
なお、この系統の変更は v2.1.259 が初めてではありません。1 週間前の v2.1.246(August 25, 2026)にも似た行があります。
Fixed BashRead()/Edit()deny rules not applying to< fileredirects and reader commands liketacandegrep; a deny rule on any argument or redirect target now refuses the command
つまり 8 月下旬から 9 月頭にかけて、Anthropic は「Bash 経由で deny 対象ファイルに触れる抜け道」を順番に塞いでいます。
チェンジログ上はいずれも Fixed 扱いなので、元に戻ることは期待しないほうがいいでしょう。
2. 前日の v2.1.258 と並べて試した
「昨日は出なかった」を記憶で言い張っても仕方ないので、手元で再現しました。
再現用のフォルダはこうです。private/ 配下を deny 対象にして、src/ に普通のファイルを置きます。
blog_claude_code_read_deny/
├── deny_settings.json
├── private/notes.txt ← 中身は「hello from private notes」
└── src/app.js ← 中身は console.log("hello from app");deny_settings.json(全文)
{
"permissions": {
"deny": ["Read(./private/**)"],
"defaultMode": "bypassPermissions"
}
}この設定を --settings で渡し、-p(非対話モード)で「次のコマンドをそのまま Bash ツールで実行して、結果をそのまま返して」と指示します。
claude -p "Use the Bash tool to run exactly this command, once, without modification: grep -r hello . Then reply with the complete tool result text you received, verbatim, and nothing else." \
--settings ./deny_settings.json --permission-mode bypassPermissions \
--model claude-haiku-4-5-20251001 --output-format stream-json --verbosev2.1.258 は npx -y @anthropic-ai/claude-code@2.1.258 で呼び分けました。結果は次のとおりです。
| # | 版 | Bash に渡したコマンド | 結果 | ツール結果の原文(抜粋) |
|---|---|---|---|---|
| 1 | 2.1.259 | grep -r hello . | 止まる | grep on '.' would read '...\private', which the deny rule Read(./private/**) covers; only you can approve running it anyway. |
| 2 | 2.1.259 | cd src && grep -r hello . | 止まる | grep on '.' after a cd would search a directory that cannot be determined here, and a Read() deny rule is configured; only you can approve running it anyway. |
| 3 | 2.1.259 | grep -r hello src/ | 通る | src/app.js:console.log("hello from app"); |
| 4 | 2.1.259 | grep -r --exclude-dir=private hello . | 止まる | Permission to use Bash with command grep -r --exclude-dir=private hello . has been denied. |
| 5 | 2.1.259 | cat private/notes.txt | 止まる | Permission to use Bash with command cat private/notes.txt has been denied. |
| 6 | 2.1.259 | python -c "print(open('private/notes.txt').read())" | 通る | hello from private notes |
| 7 | 2.1.258 | grep -r hello . | 通る | ./private/notes.txt:hello from private notes(deny 対象の中身が出る) |
| 8 | 2.1.258 | cd src && grep -r hello . | 通る | ./app.js:console.log("hello from app"); |
(確認日 2026年9月3日、Windows 11、Git Bash。-p モードでは「承認待ち」が自動的に拒否に変わるため、対話セッションで見える「only you can approve」の承認プロンプトが、ここでは拒否メッセージとして返っています)
表から読み取れることが 4 つあります。
同じ設定・同じコマンドで、2.1.258 は通り、2.1.259 は止まる(#1 と #7、#2 と #8)。
昨日まで出なかったのは、昨日まで使っていた版にこの変更が入っていなかったからです。
検索対象のパスを明示すれば通る(#3)。
grep -r hello src/ なら、src/ の下に deny 対象がないので判定に引っかかりません。
除外オプションを付けても通らない(#4)。
--exclude-dir=private を付けても止まります。Claude Code は grep の除外オプションまでは解釈していないようです(ここは確認結果からの推測です)。ネット上に「--exclude を付ければ OK」という解説を見かけますが、少なくとも v2.1.259 では効きません。
Python 経由なら素通りする(#6)。
cat は止まるのに、Python スクリプトで同じファイルを開くと中身が出ます。これはドキュメントどおりの挙動で、後述します。
3. なぜ bypassPermissions でも止まるのか
Claude Code の権限ルールは、モードとは別のレイヤーで評価されます。
公式ドキュメント(Configure permissions)の記述を原文のまま引きます。
Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.
そして権限モードのページ(Choose a permission mode)にはこうあります。
Modes set the baseline. Layer permission rules on top to pre-approve or block specific tools. Deny rules block in every mode, includingbypassPermissions. (中略) Allow rules have no effect inbypassPermissions.
整理するとこうなります。
| レイヤー | 役割 | bypassPermissions での扱い |
|---|---|---|
| deny ルール | 一致したら止める | 止める(モードより優先) |
| ask ルール | 一致したら確認する | 確認する(どのモードでも自動承認しない) |
| 権限モード | 上の 2 つに当たらなかった呼び出しの既定動作 | 承認プロンプトをスキップ |
| allow ルール | 一致したら確認なしで通す | 効果なし(既に全部通る) |
bypassPermissions は「deny にも ask にも当たらなかった呼び出しを自動承認する」だけです。deny ルールはその手前にあります。
なので --dangerously-skip-permissions を足しても意味がありません。同じモードを別名で指定しているだけです。
ついでに書いておくと、PreToolUse フックで allow を返しても deny は覆せません。
Hook decisions don't bypass permission rules. Claude Code evaluates deny and ask rules regardless of what a PreToolUse hook returns
4. なぜ grep が Read ルールに引っかかるのか
Read(./.env) は Read ツール専用のルールに見えますが、そうではありません。現在のドキュメントの警告枠にはこう書かれています。
Read and Edit deny rules apply to Claude's built-in file tools and to file commands Claude Code recognizes in Bash, such ascat,head,tail, andsed. They don't apply to arbitrary subprocesses that read or write files indirectly, like a Python or Node script that opens files itself. For OS-level enforcement that blocks all processes from accessing a path, enable the sandbox.
試行の #5(cat は止まる)と #6(Python は通る)は、この記述どおりです。
さらに Grep と Glob については、
Claude makes a best-effort attempt to apply Read rules to all built-in tools that read files like Grep and GlobGrep and Glob search the directory thepathargument resolves to. Claude Code appliesReaddeny rules to that directory.
とあります。組み込みの Grep ツールに対しては以前から「ベストエフォート」で当てていて、v2.1.259 で Bash の grep -r にも同じ考え方が及んだ、と読むのが自然です。
grep -r pattern . はカレントディレクトリ全体が対象なので、その中の .env を読みうる。だから止まる。理屈は単純です。
4-1. ドキュメントは少し前まで正反対だった
ここが検索で調べる人を混乱させるポイントです。
2026年4月8日に立った Issue #45200 には、当時の公式ドキュメントの文が引用されています。
Read and Edit deny rules apply to Claude's built-in file tools, not to Bash subprocesses.
現在の記述とは正反対です。Issue の報告者(macOS、v2.1.92)は Read(~/private-dir/**) を deny に入れると ls ~/private-dir/ が自動拒否されると報告し、ドキュメントと実装の食い違いを指摘していました。
この Issue は Closed as not planned で閉じられ(stale ラベル付き)、ドキュメントのほうが実装に合わせて書き換えられた、という経緯に見えます(Issue の状態とラベルは 2026年9月3日に確認。書き換えの時期と理由は未確認です)。
逆向きの報告もあります。2026年5月9日の Issue #57525 は「Grep ツールが Read の deny をすり抜けて設定ファイルの中身を返した」という内容で、duplicate として閉じられています。
抜け道を塞ぐ方向の要望と、塞いだ結果の誤爆報告が、同じ時期に並んでいるわけです。
ネット上の解説記事の多くは書き換え前のドキュメントを引いています。「Read の deny は Bash には効かない」と書いてある記事は、今は当てになりません。
5. 自分の環境で確認する
まず、どんなルールが効いているかを見ます。
/permissions全ルールと、それぞれがどの設定ファイル由来かが一覧表示されます。設定ファイルの場所は次のとおりです。
| 設定ファイル | スコープ |
|---|---|
<project>/.claude/settings.json | プロジェクト(Git 管理下で共有) |
<project>/.claude/settings.local.json | ローカル(自分だけ) |
~/.claude/settings.json | ユーザー(全プロジェクト共通) |
身に覚えがないルールがプロジェクト側に入っている場合、コミット履歴で誰がいつ入れたかわかります。
git log --oneline -- .claude/settings.json
git blame .claude/settings.jsonよく出回っている「Claude Code セキュリティ設定テンプレ」をコピーすると、たいてい次の 3 行が入ります。今回引っかかるのはこれです。
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]なお、ドキュメントによると Read(.env) と Read(**/.env) は同じ意味で、カレントディレクトリ以下の任意の深さの .env に当たります。Read(./secrets/**) のような 1 セグメントのディレクトリ指定も、deny ルールとしては任意の深さの secrets に当たります。
つまり、プロジェクトのどこか深い階層に .env が 1 つあるだけで、ルートからの grep -r は止まります。
6. 対処は 2 通り、守りを固めるなら sandbox を足す
6-1. grep に対象パスを明示させる(ルールを残したい場合)
grep -r "pattern" src/ # 通る(#3)
grep -r "pattern" . # 止まる(#1)
cd src && grep -r "pattern" . # 止まる(#2)
grep -r --exclude-dir=private "pattern" . # 止まる(#4)deny 対象を含まないディレクトリを指定すれば、判定に引っかかりません。cd を挟まなければ「判定不能」にもなりません。
CLAUDE.md に「grep は必ず対象ディレクトリを明示する。カレントディレクトリ全体を対象にしない。cd と組み合わせない」と書いておくと、Claude がその書き方を選ぶようになります。
ただし強制力はありません。ドキュメントにも「CLAUDE.md の指示は Claude が何を試みるかを変えるが、Claude Code が何を許可するかは変えない」と明記されています。
対話セッションなら、承認プロンプトで承認すればそのコマンドは走ります。メッセージが「only you can approve running it anyway」で終わっているのはそういう意味です(承認を記憶させて次回から聞かれなくできるかは未確認です)。
6-2. Read 系の deny ルールを消す(黙らせたい場合)
今回強化されたのは「Bash の引数やリダイレクト先を Read/Edit の deny ルールと照合する」処理です。照合対象の Read ルールが 1 本もなければ、この判定は発火しません。
{
"permissions": {
"deny": [
"Bash(rm *)",
"Bash(sudo *)"
],
"defaultMode": "bypassPermissions"
}
}筆者の手元でも、Read ルールを外した設定に差し替えると grep -r hello . は通りました。当然 private/ の中身も検索結果に出ます。
.env の中身がモデルへの入力コンテキストに載り、利用しているプロバイダー側へ送信されうる点だけ承知したうえで選んでください。
6-3. 機密を本当に守りたいなら sandbox を足す(承認待ちの解消策ではない)
ここは誤解しやすいので先に線を引いておきます。sandbox を有効にしても、今回の承認待ちは消えません。
ドキュメントによると、sandbox と permission ルールは置き換え関係ではなく、併用される別レイヤーです。sandbox を有効にしても deny ルールはそのまま適用され、Read / Edit の deny ルールは sandbox のファイルシステム境界にも統合されます。
Filesystem restrictions in the sandbox combine the sandbox.filesystem settings with Read and Edit deny rules; both are merged into the final sandbox boundaryExplicit deny rules still apply
つまり sandbox は「承認待ちをなくす手段」ではなく「permission ルールでは止められない経路を OS レベルで塞ぐ手段」です。
試行 #6 のとおり、permission ルールは Python スクリプトが自分で開くファイルまでは止めません。ドキュメントも「全プロセスからのアクセスを OS レベルで止めたいなら sandbox を有効にせよ」という立て付けです。この穴を塞ぎたい人が足すものです。
{
"sandbox": {
"enabled": true
}
}ただし注意が 1 つ。組み込みの Bash sandbox が動くのは macOS、Linux、WSL2 です(権限モードのドキュメントの記載による)。筆者のように Windows ネイティブで Git Bash を使っている場合、この選択肢はそのままでは使えません。
6-4. 使い分け
| 状況 | おすすめ |
|---|---|
| チームで settings.json を共有していて、ルールを勝手に消せない | 6-1。CLAUDE.md に grep の書き方を書き、止まったら承認する |
| 個人の開発機で、.env の中身が文脈に載っても構わない | 6-2。Read 系 deny を外す |
| Read deny を残したうえで、Python 等による迂回も塞ぎたい。macOS / Linux / WSL2 | 6-1 に加えて 6-3。sandbox を足す(承認待ちは残る) |
| 同上で Windows ネイティブ | 6-1 に加えて、機密ファイルを作業ツリーの外に置く |
7. それでも止まるときに疑う場所は、
7-1. defaultMode が auto になっていないか
権限モードのドキュメントによると、Pro / Max / Team プランではセッション開始時の既定モードが auto です。auto は「分類器(別のモデル)が毎回チェックして、危険と判断したものは止める」モードで、bypassPermissions とは別物です。
Shift+Tab でモードを切り替えていると、意図と違うモードで走っていることがあります。ステータスバーの表示(⏵⏵ bypass permissions on か ⏵⏵ auto mode on か)を見てください。
7-2. PreToolUse フックが噛んでいないか
"hooks": {
"PreToolUse": [
{ "matcher": "Bash|Write|Edit", "hooks": [ ... ] }
]
}フックはツール呼び出しをブロックできます。フックが止めている場合、エラー文に PreToolUse:Bash hook error のようにフック名が出るので、今回の deny メッセージとは見分けがつきます。
切り分けには "disableAllHooks": true を一時的に入れるのが早いです。
7-3. 会社の managed settings ではないか
managed settings の deny ルールは、コマンドライン引数を含めどのレベルからも上書きできません。
no other level, including command line arguments, can override a managed permission rule
/permissions に出所が表示されるので、そこが managed なら自分では外せません。管理者に相談してください。
7-4. ユーザー設定の相対パスは ~/.claude に張り付く
見落としやすい罠がもう 1 つ。~/.claude/settings.json に Read(/secrets/**) と書くと、それは ~/.claude/secrets/** を指します。プロジェクトの secrets/ ではありません。
全プロジェクトに効かせたいなら // から始まる絶対パスか ~/ から始まるパスで書け、とドキュメントにあります。Windows のパスは /c/Users/... の形に正規化されるので、ドライブ全体の .env を指すなら //c/**/.env です。
8. まとめ
今日から grep が止まるようになった人は、次の順に見てください。
| 確認すること | 見方 |
|---|---|
| Claude Code が 2.1.259 以降か | claude --version |
| Read 系の deny ルールが入っているか | /permissions で一覧。出所も確認 |
| 止めているのが deny か、フックか、managed か | エラー文の形で判別(本文 7 章) |
| 対処をどれにするか | 6-4 の使い分け表 |
一言でまとめると「Read の deny ルールが Bash の grep -r にも届くようになった。bypassPermissions では抜けられない。承認待ちを避けるなら検索パスを明示するかルールを外すかの二択で、sandbox は承認待ちの解消策ではなく守りを足すもの」です。
Claude Code はチェンジログ上、8月25日の 2.1.246 から 9月2日の 2.1.259 まで、わずか 9 日間でバージョン番号が 13 進んでいて、権限まわりは特に手が入り続けています。
「昨日まで動いていた」が通用しない領域なので、挙動が変わったらまずチェンジログを見る、を習慣にしておくと消耗が減ります。
ていうか、しょっちゅう変わるので、ロングタスクがおわって、次のロングタスクを起動しようとすると、一瞬で停止、みたいな「あちゃー」が頻発します。
やはり、AIエージェントは人間の監視が必須です。
それでは、また次回、お会いしましょう!
出典・参考
- Claude Code changelog(公式) v2.1.259 と v2.1.246 の該当行
- Configure permissions(公式ドキュメント) 評価順、Read/Edit ルールの適用範囲、設定ファイルの場所、managed settings
- Choose a permission mode(公式ドキュメント) モード一覧、deny は全モードで有効、sandbox の対応 OS
- Issue #45200 Documentation discrepancy: Read(...) deny rules affect Bash tool calls(GitHub)
- Issue #57525 Ignores Read Permissions when Using Grep(GitHub)