claude-code - 💡(How to fix) Fix Read-only Bash commands prompt for paths outside project even when Read tool is globally allowed [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#58568Fetched 2026-05-14 03:44:56
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Author
Timeline (top)
labeled ×4commented ×1

Root Cause

In bashToolCheckPermission() (bashPermissions.ts), the execution order is:

Step 1: Exact match check
Step 2: Prefix deny/ask rules
Step 3: checkPathConstraints()   ← returns 'ask' for external paths, SHORT-CIRCUITS here
Step 4: Allow exact match        ← never reached
Step 5: Allow prefix/wildcard    ← never reached (Bash(grep *) lives here)
Step 7: isReadOnly() check       ← never reached (read-only auto-allow lives here)

checkPathConstraints() at step 3 returns 'ask' for any path outside the project directory, short-circuiting the pipeline before the allow rules (step 5) and the read-only auto-allow check (step 7) are ever evaluated.

Fix Action

Workaround

Add explicit Read() path rules for each external directory:

"Read(/Users/me/go/pkg/mod/**)",
"Read(/usr/include/**)"

This works but is verbose, platform-specific, and conceptually redundant when Read is already globally allowed.

Code Example

grep -n "type Tool struct" ~/go/pkg/mod/github.com/some-lib@v1.0.0/types.go

---

Step 1: Exact match check
Step 2: Prefix deny/ask rules
Step 3: checkPathConstraints()   ← returns 'ask' for external paths, SHORT-CIRCUITS here
Step 4: Allow exact match        ← never reached
Step 5: Allow prefix/wildcard    ← never reached (Bash(grep *) lives here)
Step 7: isReadOnly() check       ← never reached (read-only auto-allow lives here)

---

"Read(/Users/me/go/pkg/mod/**)",
"Read(/usr/include/**)"
RAW_BUFFERClick to expand / collapse

Bug Description

Read-only Bash commands (e.g., grep, cat, head) targeting files outside the project directory trigger a permission prompt, even when:

  1. The user has globally allowed the command pattern (e.g., Bash(grep *) in ~/.claude/settings.json)
  2. The user has globally allowed the Read tool (i.e., "Read" in permissions.allow)

The same file can be read silently by Claude's Read tool, but grep on the same file triggers a confirmation prompt. This is an inconsistency — both operations have identical security impact (read-only access to the same file).

Steps to Reproduce

  1. Add Bash(grep *) and "Read" to ~/.claude/settings.json under permissions.allow
  2. Open a project (e.g., /home/user/myproject/)
  3. Ask Claude to grep a file outside the project directory, such as a Go module dependency:
    grep -n "type Tool struct" ~/go/pkg/mod/github.com/[email protected]/types.go
  4. Claude prompts for permission despite both Bash(grep *) and Read being globally allowed

Meanwhile, using Claude's Read tool on the same file passes silently.

Root Cause

In bashToolCheckPermission() (bashPermissions.ts), the execution order is:

Step 1: Exact match check
Step 2: Prefix deny/ask rules
Step 3: checkPathConstraints()   ← returns 'ask' for external paths, SHORT-CIRCUITS here
Step 4: Allow exact match        ← never reached
Step 5: Allow prefix/wildcard    ← never reached (Bash(grep *) lives here)
Step 7: isReadOnly() check       ← never reached (read-only auto-allow lives here)

checkPathConstraints() at step 3 returns 'ask' for any path outside the project directory, short-circuiting the pipeline before the allow rules (step 5) and the read-only auto-allow check (step 7) are ever evaluated.

Expected Behavior

If a Bash command is verified as read-only (grep, cat, head, etc.) and the user has globally allowed the Read tool or the specific command pattern, checkPathConstraints() should not block it. The read-only determination (step 7) or allow-rule matching (step 5) should take precedence over the coarse path constraint check.

Possible approaches:

  • Move isReadOnly() check before checkPathConstraints(), so verified read-only commands on external paths are auto-allowed
  • Have checkPathConstraints() consult the user's Read(path) rules and global Read permission before returning 'ask'
  • Check allow rules (step 5) before path constraints (step 3)

Impact

This affects any workflow that reads dependency source code outside the project directory:

  • Go module cache (~/go/pkg/mod/)
  • Rust crates (~/.cargo/registry/)
  • System headers (/usr/include/, /usr/local/include/)
  • Xcode SDKs (/Library/Developer/CommandLineTools/)

Workaround

Add explicit Read() path rules for each external directory:

"Read(/Users/me/go/pkg/mod/**)",
"Read(/usr/include/**)"

This works but is verbose, platform-specific, and conceptually redundant when Read is already globally allowed.

Environment

  • Claude Code CLI
  • macOS / Linux
  • Global settings with Bash(grep *) and "Read" in permissions.allow

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING