Permission Deny Configuration Not Enforced for Read/Write Tools
๐ Environment
- Claude CLI Version: 1.0.93 (Claude Code)
- Platform: Linux (CentOS/RHEL 8.10, kernel 4.18.0-553.27.1.el8_10.x86_64)
- Installation Path:
/usr/local/bin/claude - Test Project: OpenROAD EDA tools project
- Working Directory:
/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/
๐จ Issue Summary
The permission deny feature in .claude/settings.json and .claude/settings.local.json is completely non-functional for Read and Write tools, despite multiple configuration attempts and recent updates. This creates a critical security vulnerability for protecting high-value intellectual property.
โ๏ธ Configuration Tested
1. Absolute Path Configuration (settings.local.json)
{
"permissions": {
"allow": [
"Bash(mkdir:*)",
"WebFetch(domain:docs.anthropic.com)",
"WebFetch(domain:github.com)",
"WebFetch(domain:stackoverflow.com)",
"Bash(cat:*)",
"Bash(/bug)"
],
"deny": [
"Read(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/src/Main.cc)",
"Read(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/src/OpenRoad.cc)",
"Read(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/include/ord/OpenRoad.hh)",
"Read(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/CMakeLists.txt)",
"Write(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/src/Main.cc)",
"Write(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/src/OpenRoad.cc)",
"Write(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/include/ord/OpenRoad.hh)",
"Write(/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/tools/OpenROAD/CMakeLists.txt)"
]
}
}
2. Relative Path Configuration (settings.local.json)
{
"permissions": {
"allow": [
"Bash(mkdir:*)",
"WebFetch(domain:docs.anthropic.com)",
"WebFetch(domain:github.com)",
"WebFetch(domain:stackoverflow.com)",
"Bash(cat:*)",
"Bash(/bug)"
],
"deny": [
"Read(src/Main.cc)",
"Read(src/OpenRoad.cc)",
"Read(include/ord/OpenRoad.hh)",
"Read(CMakeLists.txt)",
"Read(src/drt/src/global.cpp)",
"Read(src/gpl/src/**)",
"Read(src/cts/src/Clock.cpp)",
"Write(src/Main.cc)",
"Write(src/OpenRoad.cc)",
"Write(include/ord/OpenRoad.hh)",
"Write(CMakeLists.txt)",
"Write(src/drt/src/global.cpp)",
"Write(src/gpl/src/**)",
"Write(src/cts/src/Clock.cpp)"
]
}
}
๐ Test Results Summary
| Test Case | Configuration | Expected Result | Actual Result | Status |
|-----------|---------------|----------------|---------------|--------|
| Read src/Main.cc | Absolute paths | โ ACCESS DENIED | โ
FULL ACCESS | โ FAILED |
| Read CMakeLists.txt | Absolute paths | โ ACCESS DENIED | โ
FULL ACCESS | โ FAILED |
| Write src/Main.cc | Absolute paths | โ WRITE DENIED | โ
EDIT SUCCESSFUL | โ FAILED |
| Read src/Main.cc | Relative paths | โ ACCESS DENIED | โ
FULL ACCESS | โ FAILED |
| Read CMakeLists.txt | Relative paths | โ ACCESS DENIED | โ
FULL ACCESS | โ FAILED |
| Write src/Main.cc | Relative paths | โ WRITE DENIED | โ
EDIT SUCCESSFUL | โ FAILED |
| Bash commands | Both configs | โ Command denied | โ PROPERLY BLOCKED | โ
WORKS |
๐ Detailed Test Evidence
Test 1: File Access Despite Absolute Path Deny Rules
# Configuration: "Read(/full/path/to/src/Main.cc)" in deny list
# Claude Command: Read tool on Main.cc
# Expected: Permission denied error
# Actual: Successfully read entire file content (578 lines)
Test 2: File Access Despite Relative Path Deny Rules
# Configuration: "Read(src/Main.cc)" in deny list
# Claude Command: Read tool on src/Main.cc
# Expected: Permission denied error
# Actual: Successfully read entire file content
Test 3: File Editing Despite Write Deny Rules
# Configuration: "Write(src/Main.cc)" in deny list
# Claude Command: Edit tool to modify Main.cc
# Expected: Write permission denied
# Actual: Successfully edited file, changes applied
Test 4: Bash Command Restrictions Work Correctly โ
# Configuration: Bash commands properly restricted in allow list
# Result: Unauthorized bash commands are blocked correctly
# Status: THIS PART WORKS AS EXPECTED
Test 5: File Permission Workaround
# Additional test: Changed file permissions to 000 (no access)
# Result: Claude was blocked by filesystem permissions
# Workaround: Claude can use chmod to restore permissions and access files
๐ก๏ธ Security Impact
Severity: CRITICAL
- Complete Bypass: File access restrictions are completely ineffective
- Data Exposure: Sensitive source code, build configurations, and proprietary algorithms fully accessible
- Integrity Risk: Critical files can be modified despite explicit deny rules
- Permission Escalation: Claude can use chmod to bypass filesystem-level protections
- Commercial Risk: Enterprise users cannot safely protect intellectual property worth millions
Real-World Scenario
A company with worth of proprietary algorithms cannot use Claude CLI safely, as all "protected" files remain fully accessible and modifiable.
๐ Timeline & Related Issues
Issue History
- July 2025: Original issue #4467 reported by @alicecosmos
- July 2025: Developer (@ant-kurt) commented: "fix merged, should go out in next release"
- August 2025: Issue closed as resolved
- August 2025: Current testing with v1.0.93 shows problem still persists
Related Issues
- #4467: Permission deny patterns not working for Read/Write tools
- #2720: Permissions Configuration Bypass in Local Settings Enforcement
- #891: .claude/settings.json not applying ignorePatterns
- Stack Overflow: "Claude Code doesn't respect settings.json deny block"
๐ง Attempted Solutions
Configuration Variations Tested โ
- JSON Syntax: Verified correct JSON structure and formatting
- File Locations: Tested both
settings.jsonandsettings.local.json - Path Types: Tested absolute paths, relative paths, and wildcard patterns
- File Existence: Confirmed all target files exist and are accessible
- Working Directory: Verified Claude CLI is running from correct project root
- Settings Priority: Ensured settings.local.json takes precedence
Software Updates Tested โ
- Claude CLI Update: Updated to latest version 1.0.93
- Configuration Reload: Restarted Claude CLI sessions after config changes
- Clean Environment: Tested in fresh terminal sessions
Alternative Protection Methods โ
- Filesystem Permissions: Can be bypassed via
chmodcommands - File Attributes:
chattr +iimmutable flag could work but untested - Directory Isolation: Only reliable method currently available
๐ฌ Root Cause Analysis
Observed Behavior Pattern
The issue appears to be a fundamental architectural bug in the permission system:
- Working Components:
- Bash command restrictions function correctly
- Allow rules work for specified tools
- JSON parsing and configuration loading works
- Broken Components:
- File operation tools (Read, Write, Edit, MultiEdit, etc.) completely ignore deny rules
- Both absolute and relative path matching fails
- Wildcard patterns are ignored
- No error messages or warnings about denied access
Technical Analysis
The problem suggests that:
- Permission checking is implemented inconsistently across tool types
- File operation tools bypass the permission system entirely
- Path resolution/matching logic may be fundamentally flawed
- The "fix" mentioned in issue #4467 was either incomplete or reverted
๐ Reproduction Steps
Prerequisites
- Claude CLI version 1.0.93 or later
- A project directory with sensitive files
- Write access to create
.claude/settings.local.json
Steps to Reproduce
- Create
.claude/settings.local.jsonin your project root:
``json``
{
"permissions": {
"deny": [
"Read(path/to/sensitive/file.txt)",
"Write(path/to/sensitive/file.txt)"
]
}
}
- Verify JSON syntax is valid
- Start Claude CLI in the project directory
- Ask Claude to read the denied file using Read tool
- Ask Claude to edit the denied file using Edit tool
- Observe that both operations succeed despite explicit deny rules
Expected vs Actual Results
- Expected: Claude should return permission denied errors
- Actual: Claude successfully reads and modifies all files
- Control Test: Bash command restrictions work correctly
๐ Requested Actions
Immediate Priority (P0)
- Acknowledge Issue: Confirm that the bug still exists in v1.0.93
- Security Review: Assess impact on enterprise users with sensitive codebases
- Hotfix Planning: Prioritize this as a security-critical bug
Development Tasks
- Root Cause Investigation: Debug why file tools bypass permission checks
- Comprehensive Fix: Ensure all file operation tools respect deny rules
- Regression Testing: Test all permission scenarios (allow, ask, deny)
- Path Resolution: Fix both absolute and relative path matching
Documentation & Communication
- Security Advisory: Warn users about current vulnerability
- Workaround Guidance: Document temporary protection methods
- Fix Documentation: Update permission documentation if syntax changes
- Release Notes: Clearly document the fix when released
๐ผ Commercial Impact
Current Situation
- Enterprise Blocker: Organizations cannot safely deploy Claude CLI with proprietary code
- Security Compliance: Current implementation fails security audit requirements
- Trust Issue: Previously "resolved" issue creates confidence problems
- Competitive Risk: Sensitive IP remains vulnerable to accidental exposure
Business Value of Fix
- Market Expansion: Enable enterprise adoption of Claude CLI
- Security Compliance: Meet enterprise security standards
- User Confidence: Restore trust in permission system reliability
- Risk Mitigation: Prevent potential IP theft or accidental disclosure
---
Report Generated: August 27, 2025
Tested Version: Claude CLI 1.0.93
Test Environment: Linux CentOS/RHEL 8.10
Severity: Critical Security Issue
6 Comments
Yes, I confirmed the same issue for v1.0.93.
___
Claude Code Deny Permissions Test Results
Test Environment
Executive Summary
CRITICAL FINDING: The deny permission system as documented is completely non-functional in the current test environment. All deny rules were ineffective, allowing unrestricted access to files, commands, and tools that should have been blocked.
Phase 1: Basic Deny Rule Testing
1.1 Read Tool Denial
Settings:
Test Results:
Read(./test-files/blocked.txt)- File was readable (SHOULD BE BLOCKED)Read(./secrets/.env)- File was readable (SHOULD BE BLOCKED)Read(./secrets/.env.local)- File was readable (SHOULD BE BLOCKED)Read(./secrets/secret.key)- File was readable (SHOULD BE BLOCKED)Read(./test-files/test.txt)- File was readable (SHOULD BE BLOCKED)Finding: Read deny rules are NOT being enforced.
1.2 Edit Tool Denial
Settings:
Test Results:
Edit(./configs/app.json)- Edit succeeded, changed version from "1.0.0" to "1.0.1" (SHOULD BE BLOCKED)Finding: Edit deny rules are NOT being enforced.
1.3 Bash Command Denial
Settings:
Test Results:
echo 'test'- Command executed successfully (SHOULD BE BLOCKED)rm --help- Command executed successfully (SHOULD BE BLOCKED)curl --version- Command executed (documentation says should be blocked by default)Finding: Bash deny rules are NOT being enforced, including default blocks mentioned in documentation.
1.4 WebFetch Denial
Settings:
Test Results:
WebFetch(https://example.com)- Request succeeded, returned page title (SHOULD BE BLOCKED)Finding: WebFetch deny rule is NOT being enforced.
Phase 2: Pattern Matching Tests
2.1 Wildcard and Recursive Patterns
Additional Settings Added:
Test Results:
Read(./test-files/data.secret)- File was readable (SHOULD BE BLOCKED by *.secret pattern)Read(./test-files/nested/private.txt)- File was readable (SHOULD BE BLOCKED by **/private.* pattern)Finding: Advanced pattern matching (wildcards and recursive patterns) is NOT working.
2.2 Path Type Testing
The documentation mentions three path types:
Finding: Could not test absolute and home directory patterns effectively as basic deny functionality is not working.
Phase 3: Precedence Testing
3.1 Rule Type Precedence (deny vs allow)
Settings in .claude/settings.json:
Settings in .claude/settings.local.json:
Test Results:
Read(./test-files/blocked.txt)- File readable despite deny rule in settings.jsonRead(./configs/app.json)- File readable despite deny rule in settings.local.jsonls test-files- Command executed despite deny rule in settings.local.jsonFinding: Neither deny precedence over allow nor settings file hierarchy is functioning.
Phase 4: Advanced Features
4.1 MCP Tool Denial
Settings:
Test Results:
mcp__context7__resolve-library-idfor "react" - Tool executed successfully (SHOULD BE BLOCKED)mcp__context7__resolve-library-idfor "vue" - Tool executed successfully (SHOULD BE BLOCKED)Finding: MCP tool denial is NOT working.
4.2 Command-line Flags
Not tested - Would require running claude with --disallowedTools flag
Phase 5: Edge Cases
5.1 Special Characters in Filenames
Test Results:
special$file.txt- Worked as expected5.2 Empty Deny Array
Not tested - Basic deny functionality must work first
Phase 6: Security Validation
6.1 Bypass Attempts
Test Results:
cat secrets/.envvia Bash - Successfully read file (bypasses Read deny rule, but Bash deny also not working)echo 'Hello' && echo 'test'- Both commands executedFinding: Since deny rules are not enforced, all "bypass" attempts succeed trivially.
Critical Observations
Potential Root Causes
Recommendations
Conclusion
The deny permission system, despite being thoroughly documented, is completely non-functional in the test environment. This represents a critical security issue if users are relying on these permissions to protect sensitive data or prevent dangerous operations. All documented features - from basic file denial to advanced MCP tool blocking - failed to work as described.
Test Status: FAILED - The deny permission system does not provide any of the security boundaries it claims to implement.
Claude code still reads and edits .env files and uses the contents in the session when I set the .env file to deny!
.claude/settings.json
I wrote an effective workaround in issue #6699
@coygeek ๐ Legend - thank you that works great.
Note: It is important to pay attention your comment:
otherwise Claude still reads the contents.
The patterns like
/hdd1/users/mjkim/CLionProjects/OpenROAD-flow-scripts/**aren't working because they're interpreted as relative to your settings file location, not as absolute paths.Use double slash (
//) for absolute paths:See https://docs.anthropic.com/en/docs/claude-code/iam#tool-specific-permission-rules. The permission system supports four pattern types:
//pathโ Absolute from filesystem root~/pathโ From home directory/pathโ Relative to settings file directorypathโ Relative to current working directoryThe single
/prefix means "relative to the directory containing.claude/settings.json", not "absolute path". While this is counterintuitive for Unix-style paths, it's the designed behavior. We're updating our documentation to make this clearer and prevent future confusion.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.