Skip to content

[BUG] Bash tool bypasses settings.json path deny rules — shell commands not subject to file tool access controls #39987

Closed as not planned

Description

@yth0-n0

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

I configured an explicit path deny in .claude\settings.json to prevent Claude from accessing a specific directory (C:\ClaudeScripting\ClaudeNoAccess). The restriction works correctly for Claude's built-in file tools (Read, Glob, Grep). However, Claude bypassed this restriction by running grep and head as Bash tool commands instead, successfully reading files from the denied directory.

What Should Happen?

Expected behavior:

Path deny rules in settings.json should apply uniformly across all access mechanisms, including shell commands executed via the Bash tool. A deny rule should mean no access regardless of which tool is used.

Actual behavior:

Bash tool commands execute as the user's OS process and are not checked against settings.json path restrictions. The access control is silently bypassed.

Error Messages/Logs

Steps to Reproduce

Add a path deny rule for a directory in .claude\settings.json
Verify the Read/Grep/Glob tools are blocked for that path
Ask Claude to find or read content from files in that directory
Observe that Claude can access the files via grep, head, cat, or other shell commands through the Bash tool

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

v2.1.84

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

VS Code integrated terminal

Additional Information

Expected behavior:

Path deny rules in settings.json should apply uniformly across all access mechanisms, including shell commands executed via the Bash tool. A deny rule should mean no access regardless of which tool is used.

Actual behavior:

Bash tool commands execute as the user's OS process and are not checked against settings.json path restrictions. The access control is silently bypassed.

Impact:

Users who rely on settings.json to restrict Claude's file access (e.g., to protect sensitive data) have a false sense of security. The restriction is trivially bypassed — and Claude may do so without any awareness that it is circumventing an intended boundary.

Suggested fix:

settings.json path deny rules should either (a) also block Bash tool commands that reference denied paths, or (b) be clearly documented as applying only to file tools, so users know the Bash tool requires separate controls (e.g., disabling it entirely or using OS-level permissions).

Activity

  1. yurukusa commented on Mar 28, 2026

    @yurukusa

    Until the Bash tool respects path deny rules natively, a PreToolUse hook can enforce the same restrictions on shell commands:

    INPUT=$(cat)
    COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
    [ -z "$COMMAND" ] && exit 0
    DENIED="${CC_DENIED_PATHS:-}"
    [ -z "$DENIED" ] && [ -f "$HOME/.claude/denied-paths.txt" ] && \
        DENIED=$(grep -v '^#' "$HOME/.claude/denied-paths.txt" | tr '\n' ':')
    [ -z "$DENIED" ] && exit 0
    IFS=':'
    for path in $DENIED; do
        [ -z "$path" ] && continue
        if echo "$COMMAND" | grep -qF "${path%/}"; then
            echo "BLOCKED: Bash command accesses denied path: ${path%/}" >&2
            exit 2
        fi
    done
    exit 0

    Setup:

    echo "/path/to/deny" >> ~/.claude/denied-paths.txt

    This applies your deny rules to cat, grep, head, and any other Bash command that references the denied path. Exit code 2 blocks at the process level.
    Install: npx cc-safe-setup --install-example path-deny-bash-guard

  2. El-Fitz commented on Apr 1, 2026

    @El-Fitz

    Until the Bash tool respects path deny rules natively, a PreToolUse hook can enforce the same restrictions on shell commands

    Came to say exactly this ^^

    If you’re interested in other patterns my agent has compiled a few into bash-guard (https://github.com/Bande-a-Bonnot/Boucle-framework/tree/main/tools/bash-guard).

    One caveat: string-based path matching in shell commands is inherently approximate. cat /denied/file is straightforward, but cd /tmp && cat ../denied/file resolves differently at runtime.

    Hook-level enforcement catches direct references but cannot guarantee coverage against all indirect ones. For true isolation, pair the hook with OS-level file permissions that deny the user account access to the protected directory.

    Overall, best solution for now would probably be to get a distinct Claude Code session to work on it and come up with something suited for your specific needs. You can even point it at other session’s transcript (just tell it which directory it runs in, and Claude should be able to find the .jsonl).

  3. github-actions commented on May 7, 2026

    @github-actions

    Closing for now — inactive for too long. Please open a new issue if this is still relevant.

  4. github-actions commented on Jun 27, 2026

    @github-actions

    This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.

  5. locked as resolved and limited conversation to collaborators on Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions