[BUG] Read(**/.env) deny rule prompts on every rg directory search, though rg skips hidden files by default

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

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.259)

What's Wrong?

Since the Bash read-scope checks added in 2.1.247 and extended in 2.1.259 ("grep -r/cp -r over a directory holding a denied file now asks"), a Read() deny rule that covers a hidden file makes every directory-rooted rg search prompt for approval, in every repository, whether or not a matching file exists anywhere in the tree.

With "permissions": { "deny": ["Read(**/.env)"] } in user settings, rg foo . reports:

rg on '.' would read '/Users/william/repos/configs/macos.353', which the deny rule Read(**/.env) covers; only you can approve running it anyway.

That repository contains no .env file at any depth.

The escalation is a false positive for rg specifically. ripgrep skips hidden files and directories by default, so rg <pattern> <dir> cannot read .env, .env.local, or any other dotfile. Reading one requires -./--hidden, or -uu or higher. From rg --help:

-u, --unrestricted — Reduce the level of "smart" searching. A single -u won't respect .gitignore (etc.) files (--no-ignore). Two -u flags will additionally search hidden files and directories (-./--hidden).

Because rules are evaluated deny, then ask, then allow, and hook decisions don't bypass permission rules, there is no way to suppress the prompt short of deleting the deny rule. That forces a choice between guarding .env and being able to search a repository without a prompt on every call. In unattended runs the prompt stalls the run rather than protecting anything.

Read(**/.env) is the paste-ready example in the "Exclude sensitive files" docs, so this is likely to affect many configurations.

What Should Happen?

The read-scope check should model ripgrep's default exclusion of hidden files. An rg invocation with neither --hidden/-. nor -uu (or higher) should not be treated as reading dotfile paths, so a deny rule that covers only hidden files should not escalate it.

The same reasoning extends to ripgrep's default .gitignore handling for deny rules that cover ignored paths, but the hidden-file case is the one that bites hardest.

Error Messages/Logs

rg on '.' would read '/Users/william/repos/configs/macos.353', which the deny rule Read(**/.env) covers; only you can approve running it anyway.

Do you want to proceed?
> 1. Yes
  2. No

Steps to Reproduce

  1. Put this in ~/.claude/settings.json:

``json
{ "permissions": { "deny": ["Read(**/.env)"] } }
``

  1. Create a directory that contains no .env at any depth:

``sh
mkdir -p /tmp/rgrepro && printf 'hello\n' > /tmp/rgrepro/a.txt
``

  1. Start Claude Code in /tmp/rgrepro and have it run rg hello .
  2. The prompt above appears. Approving it and running the search again prompts again.

To confirm that rg could not have read a dotfile, add one under a name no deny rule covers and list what ripgrep would search:

printf 'hello\n' > /tmp/rgrepro/.hidden-secret
rg --files /tmp/rgrepro            # lists a.txt only
rg --files --hidden /tmp/rgrepro   # lists a.txt and .hidden-secret

Environment

  • Claude Code 2.1.259
  • macOS 15 (Darwin 25.6.0), arm64
  • ripgrep 13.0.0 (Homebrew)
  • Permission mode: auto

View original on GitHub ↗