`grep -r` with `--include` filters falsely triggers `Read(.env)` deny prompt (v2.1.259) — breaks every recursive search

Status Open
Reported on v2.1.259
Maintainer reply None cached
Activity 2 comments · opened Sep 3, 2026

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 --include globs 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 .env at 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 Bash Read() deny rules not covering files given as option values (--ignore-revs-file=.env, -f.env, @file), git diff/git grep file operands, or cd DIR && cat FILE compounds; grep -r/cp -r over 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

  1. In a repo with a .env file at the root, add "deny": ["Read(.env)"] to .claude/settings.json permissions.
  2. Update Claude Code to 2.1.259.
  3. Ask Claude to find files referencing some identifier; it will run grep -r … --include='*.ts' . (or similar).
  4. Observe the Read(.env) approval prompt even though grep's include filters exclude .env.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗