[BUG] Regression in 2.1.259: rg reading stdin in a pipeline is treated as a search of '.' and prompts (auto mode bypassed) when a Read() deny rule covers a file under the cwd
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Since 2.1.259, when a Read() deny rule covers a file somewhere under the current working directory, every rg invocation that has no path operand prompts for manual approval. In a pipeline, rg with no path reads stdin and never touches the filesystem, but the Bash read-scope check models it as rg on '.' and escalates:
rg on '.' would read '<absolute path of the cwd>', which the deny rule Read(**/private-notes.md) covers; only you can approve running it anyway.
The escalation carries classifier_approvable: false, so in auto mode the classifier is skipped and a human has to click through every cmd | rg pattern. grep in the same position is handled correctly. An explicit stdin operand (rg pattern -) does not help.
In this setup every repository keeps a private-notes.md at its root that the deny rule protects, so nearly every filter pipeline the model writes now prompts, and the auto-mode classifier can do nothing about it.
Results on 2.1.259, same checkout, same deny rule, captured headless with --input-format stream-json --output-format stream-json --permission-prompt-tool stdio:
| Command | Result |
| --- | --- |
| rg -c pattern /tmp/dir/a.txt \| rg -v ':0$' \| wc -l | prompts (reason above) |
| printf 'a\nb\n' \| rg a - | prompts (same reason) |
| printf 'a\nb\n' \| grep a | runs |
| rg -c pattern /tmp/dir/*.txt (literal path with a glob) | runs |
| echo "$(rg -c pattern /tmp/dir/a.txt \| wc -l)" (substitution, literal file) | runs |
| rg -n pattern src/sub/dir/ (directory with no covered file below it) | runs |
| git diff --stat; git grep -n pattern -- src/sub | runs |
The first row was also run against the 2.1.258 binary with the same settings and checkout: it runs without a prompt.
What Should Happen?
An rg invocation with no path operand, or with -, inside a pipeline reads stdin and should not be modelled as a search of .. It should be treated the way grep already is in the same position: no deny-rule escalation, so the permission mode decides as it did before 2.1.259.
Error Messages/Logs
rg on '.' would read '<absolute path of the cwd>', which the deny rule Read(**/private-notes.md) covers; only you can approve running it anyway.
# can_use_tool control request for the same command:
"tool_name": "Bash",
"decision_reason_type": "subcommandResults",
"classifier_approvable": false,
"matched_ask_rule": null
Steps to Reproduce
- Put a
Read()deny rule in~/.claude/settings.json:
``json``
{ "permissions": { "deny": ["Read(**/private-notes.md)"] } }
- Create a directory whose root contains a file the rule covers, plus an ordinary file:
``sh``
mkdir -p /tmp/rgpipe && printf 'private\n' > /tmp/rgpipe/private-notes.md && printf 'ok\n' > /tmp/rgpipe/a.txt
- Start Claude Code 2.1.259 in
/tmp/rgpipein auto mode and have it run:
``sh``
rg -c ok /tmp/rgpipe/a.txt | rg -v ':0$' | wc -l
The prompt above appears, with classifier_approvable: false, so auto mode cannot approve it.
- Have it run
printf 'a\nb\n' | grep a. No prompt. - Repeat step 3 on 2.1.258. No prompt.
The commands in the table were run in a repository checkout whose root holds the covered file; the steps above are that setup reduced to a temp directory.
Claude Model
Other: Fable 5.1 (claude-fable-5-1). The check is static and does not depend on the model.
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.258
Claude Code Version
2.1.259 (Claude Code), the native binary bundled with the VS Code extension 2.1.259; the headless reproduction used the same binary.
Platform
Anthropic API (claude.ai subscription sign-in)
Operating System
Ubuntu/Debian Linux: Ubuntu 26.04.1 LTS, kernel 7.0.0-30-generic, ripgrep 15.1.0
Terminal/Shell
Other: VS Code extension chat panel; the Bash tool runs zsh. Also reproduced headless with claude -p --input-format stream-json --output-format stream-json --permission-prompt-tool stdio.
Additional Information
Two reports filed today trace back to the same 2.1.259 changelog line and form a cluster with this one:
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
- #91681:
rg <pattern> .with a hidden-file rule (Read(**/.env)) prompts although no covered file exists and ripgrep skips dotfiles by default. - #91683:
cd DIR && grep …prompts inbypassPermissionsmode when anyRead()rule is configured.
This report differs from both: rg has no path operand at all and reads stdin, the covered file exists and is not hidden, and grep in the identical position is unaffected. Fixing the hidden-file modelling from #91681 would not fix this case.
Workaround for now: have the model use grep for pipe filtering, or remove the deny rule. The rule protects a real file in every repository, so removing it is not an acceptable long-term answer.
_Drafted by Claude (Anthropic AI assistant)._