`grep -r` with `--include` filters falsely triggers `Read(.env)` deny prompt (v2.1.259) — breaks every recursive search
Environment
- Claude Code version: 2.1.259 (behaviour appeared with this release, 2026-09-02)
- Platform: Linux, MacOS
- Permissions config:
deny: ["Read(.env)"](and similar.env*patterns)
Description
Since v2.1.259, any recursive grep -r / rg over a directory that contains a .env file now prompts for user approval with a Read-deny warning — even when the command's own --include / --exclude filters make it impossible for grep to open .env.
Example command Claude ran:
grep -rIl -e usageEvent -e UsageEvent -e usage-event \
--include='*.js' --include='*.ts' --include='*.tsx' --include='*.coffee' \
--exclude-dir=node_modules . | head -50
Prompt shown:
grep on '.' would read '/home/<user>/code/<repo>/.env', which the deny rule
Read(.env) covers; only you can approve running it anyway.
This is a false positive: with --include='*.js' --include='*.ts' … grep only opens files matching those globs. .env is never read.
Expected behaviour
The Bash read-analysis should account for grep's --include / --exclude / --exclude-dir (and ripgrep's -g / --glob / -t) when deciding which files a recursive search "would read". A recursive search whose filters exclude every denied file should not prompt.
If full filter modelling is out of scope, at minimum:
- treat a recursive search whose
--includeglobs cannot match the denied filename as not reading it, or - provide a way to allow-list these searches (e.g. honour
Bash(grep -r *)allow rules ahead of the Read-deny escalation), or - make the escalation opt-in / configurable.
Actual behaviour
Every recursive grep over the repo root prompts. In a normal coding session Claude runs these constantly, so the effect is a permission prompt on nearly every search step. This can't be pre-approved (the prompt says "only you can approve"), so it defeats auto-accept/acceptEdits modes and any unattended usage. Multiple people on our team hit this immediately after updating.
Impact
- Breaks the core "let Claude explore the codebase" loop for any repo that has a
.envat the root (i.e. most web projects). - Regression: the same commands ran without prompting on 2.1.258 and earlier.
- Workarounds (always grepping a subdirectory, or forcing Claude to use the built-in Grep tool) are unreliable because the model chooses the search command itself.
Related changelog entry (v2.1.259)
Fixed BashRead()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
The option-value and cp -r cases make sense; the grep -r case needs filter awareness to avoid being a blanket prompt on all recursive searches.
Steps to reproduce
- In a repo with a
.envfile at the root, add"deny": ["Read(.env)"]to.claude/settings.jsonpermissions. - Update Claude Code to 2.1.259.
- Ask Claude to find files referencing some identifier; it will run
grep -r … --include='*.ts' .(or similar). - Observe the Read(.env) approval prompt even though grep's include filters exclude
.env.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗