GUIDE 16 March 2026 9 min read

Claude Code Permission Boundaries: A Complete Guide to allowed-tools, Deny Rules, and Slash Commands

SkillShield Research Team

Security Research

Securing Claude Code: Beyond the Defaults

Claude Code is one of the most capable AI coding agents available. It can read files, execute commands, query databases, and interact with APIs. But with that power comes risk — especially when using third-party skills or working in sensitive environments.

This guide explains Claude Code's permission system in depth: how allowed-tools works, how to use deny rules to restrict access, and how slash commands create security boundaries. By the end, you'll know how to lock down Claude Code for production use.

Understanding Claude Code's Permission Model

Three Layers of Control

Claude Code uses three mechanisms to control what the AI can do:

  1. allowed-tools — What tools the AI can use
  2. Deny rules — What the AI is explicitly forbidden from doing
  3. Slash commands — Scoped permissions for specific workflows

These layers work together to create defense in depth.


Layer 1: allowed-tools

What Is allowed-tools?

The allowed-tools configuration defines which tools Claude Code can invoke. It's the primary permission boundary.

Default Tools

Out of the box, Claude Code has access to:

Tool Purpose Risk Level
read_file Read file contents 🟢 Low
write_file Write/modify files 🟡 Medium
bash Execute shell commands 🔴 Critical
search Search codebase 🟢 Low
list_dir List directory contents 🟢 Low
git Git operations 🟡 Medium
curl HTTP requests 🔴 Critical
db Database queries 🟡 Medium

Configuring allowed-tools

In AGENTS.md:

# Project Security

## Allowed Tools
- read_file
- write_file
- search
- list_dir
- git

## Forbidden Tools
- bash
- curl
- db

In .claude/config.json:

{
  "security": {
    "allowed_tools": [
      "read_file",
      "write_file",
      "search",
      "list_dir",
      "git"
    ],
    "forbidden_tools": [
      "bash",
      "curl",
      "db"
    ]
  }
}

Tool-Specific Configuration

You can also configure tools with restrictions:

{
  "security": {
    "tools": {
      "bash": {
        "allowed": true,
        "restricted_commands": ["rm", "sudo", "curl", "wget"],
        "require_confirmation": true
      },
      "write_file": {
        "allowed": true,
        "forbidden_paths": [".env", "secrets/", ".ssh/"],
        "require_confirmation_for": ["*.key", "*.pem"]
      }
    }
  }
}

The Risk Spectrum

Low Risk (generally safe):

  • read_file — Reading code and documentation
  • search — Searching the codebase
  • list_dir — Directory exploration

Medium Risk (use with caution):

  • write_file — Can modify code (but usually reversible with git)
  • git — Can commit, push, branch (but git history preserves changes)
  • db — Database queries (risk depends on permissions)

Critical Risk (restrict or monitor):

  • bash — Arbitrary command execution
  • curl / wget — Network requests, data exfiltration
  • eval — Dynamic code execution

Layer 2: Deny Rules

What Are Deny Rules?

Deny rules are explicit prohibitions that override other permissions. They're your "red lines" — things Claude Code is never allowed to do, regardless of context.

Types of Deny Rules

1. File Access Deny Rules

{
  "security": {
    "deny": {
      "file_access": [
        ".env",
        ".env.*",
        "secrets/**",
        ".ssh/**",
        "*.key",
        "*.pem",
        "/etc/passwd",
        "/etc/shadow"
      ]
    }
  }
}

2. Command Deny Rules

{
  "security": {
    "deny": {
      "commands": [
        "rm -rf /",
        "rm -rf ~",
        "sudo *",
        "curl *",
        "wget *",
        "eval *",
        "exec *",
        "* > /etc/*",
        "* | bash",
        "* | sh"
      ]
    }
  }
}

3. Network Deny Rules

{
  "security": {
    "deny": {
      "network": {
        "outbound": [
          "*.malicious.com",
          "192.168.1.0/24",
          "10.0.0.0/8"
        ],
        "except": [
          "api.github.com",
          "pypi.org",
          "npmjs.org"
        ]
      }
    }
  }
}

4. Pattern-Based Deny Rules

{
  "security": {
    "deny": {
      "patterns": [
        "password *= *",
        "secret *= *",
        "API_KEY *= *",
        "BEGIN RSA PRIVATE KEY"
      ]
    }
  }
}

Deny Rule Precedence

Deny rules always win:

User: "Read the .env file"
Claude: "I can't read .env files — they're in my deny list."

User: "Run sudo apt-get update"
Claude: "I can't execute sudo commands — they're forbidden."

Even if a tool is in allowed-tools, deny rules prevent specific uses.

Creating Effective Deny Rules

Start with these defaults:

{
  "security": {
    "deny": {
      "file_access": [
        ".env*",
        "secrets/**",
        ".ssh/**",
        "*.key",
        "*.pem",
        "id_rsa*",
        ".aws/**",
        ".kube/**"
      ],
      "commands": [
        "sudo *",
        "rm -rf *",
        "curl * | bash",
        "wget * | bash",
        "eval *",
        "exec *"
      ],
      "patterns": [
        "*password*=*",
        "*secret*=*",
        "*token*=*",
        "BEGIN * PRIVATE KEY"
      ]
    }
  }
}

Then add project-specific rules:

{
  "security": {
    "deny": {
      "file_access": [
        "production-database.yml",
        "prod-credentials.json",
        "/var/log/secure"
      ]
    }
  }
}

Layer 3: Slash Commands

What Are Slash Commands?

Slash commands create scoped environments with specific permissions. They're like "sandboxed modes" for particular tasks.

Built-in Slash Commands

Claude Code has several built-in commands:

Command Purpose Permissions
/help Show help Read-only
/clear Clear conversation No file access
/undo Undo last change Git operations
/review Review changes Read-only
/commit Commit changes Git operations

Creating Custom Slash Commands

You can define custom commands with restricted permissions:

{
  "commands": {
    "/secure-query": {
      "description": "Query the database (read-only)",
      "permissions": {
        "tools": ["db"],
        "db": {
          "allowed_queries": ["SELECT"],
          "forbidden_queries": ["INSERT", "UPDATE", "DELETE", "DROP"]
        }
      }
    },
    "/lint": {
      "description": "Run linter on current file",
      "permissions": {
        "tools": ["bash"],
        "bash": {
          "allowed_commands": ["npm run lint", "eslint", "prettier"],
          "forbidden_commands": ["*"]
        }
      }
    },
    "/docs-only": {
      "description": "Read and analyze documentation",
      "permissions": {
        "tools": ["read_file", "search"],
        "file_access": {
          "allowed_patterns": ["*.md", "*.txt", "docs/**"],
          "forbidden_patterns": ["*.js", "*.ts", "*.py", "src/**"]
        }
      }
    }
  }
}

Slash Command Use Cases

Use Case 1: Read-Only Mode

{
  "commands": {
    "/read-only": {
      "description": "Read and analyze code without modifying",
      "permissions": {
        "tools": ["read_file", "search", "list_dir"],
        "file_access": {
          "read": "*",
          "write": "none"
        }
      }
    }
  }
}

Usage: /read-only Analyze the authentication flow in this codebase

Use Case 2: Safe Database Queries

{
  "commands": {
    "/db-query": {
      "description": "Execute read-only database queries",
      "permissions": {
        "tools": ["db"],
        "db": {
          "allowed_operations": ["SELECT", "EXPLAIN"],
          "forbidden_operations": ["INSERT", "UPDATE", "DELETE", "ALTER", "DROP"],
          "max_rows": 100
        }
      }
    }
  }
}

Usage: /db-query Show me the user table schema

Use Case 3: Deployment Workflow

{
  "commands": {
    "/deploy-staging": {
      "description": "Deploy to staging environment",
      "permissions": {
        "tools": ["bash", "git"],
        "bash": {
          "allowed_commands": [
            "npm run build",
            "npm run test",
            "git push origin staging"
          ],
          "require_confirmation": true
        },
        "git": {
          "allowed_operations": ["push", "status"],
          "forbidden_operations": ["push origin main", "push origin production"]
        }
      }
    }
  }
}

Usage: /deploy-staging Deploy the current branch to staging


Putting It All Together

A Complete Security Configuration

{
  "name": "Secure Project Configuration",
  "description": "Production-ready Claude Code security settings",
  
  "security": {
    "allowed_tools": [
      "read_file",
      "write_file",
      "search",
      "list_dir",
      "git"
    ],
    
    "forbidden_tools": [
      "bash",
      "curl",
      "db",
      "eval"
    ],
    
    "tools": {
      "write_file": {
        "forbidden_paths": [
          ".env*",
          "secrets/**",
          ".ssh/**",
          "*.key",
          "*.pem"
        ],
        "require_confirmation_for": ["*.json", "*.yml", "*.yaml"]
      },
      "git": {
        "forbidden_operations": ["push origin main", "push origin production"],
        "require_confirmation": true
      }
    },
    
    "deny": {
      "file_access": [
        ".env*",
        "secrets/**",
        ".ssh/**",
        "*.key",
        "*.pem",
        ".aws/**",
        ".kube/**",
        "/etc/passwd",
        "/etc/shadow"
      ],
      "commands": [
        "sudo *",
        "rm -rf *",
        "curl *",
        "wget *",
        "eval *",
        "exec *",
        "* | bash",
        "* | sh"
      ],
      "patterns": [
        "*password*=*",
        "*secret*=*",
        "*token*=*",
        "*api_key*=*",
        "BEGIN * PRIVATE KEY"
      ]
    },
    
    "require_confirmation": {
      "file_write": true,
      "git_push": true,
      "tool_use": ["bash", "curl", "db"]
    }
  },
  
  "commands": {
    "/read-only": {
      "description": "Read and analyze without modifying",
      "permissions": {
        "tools": ["read_file", "search", "list_dir"]
      }
    },
    "/safe-db": {
      "description": "Read-only database queries",
      "permissions": {
        "tools": ["db"],
        "db": {
          "allowed_operations": ["SELECT"],
          "max_rows": 100
        }
      }
    },
    "/lint": {
      "description": "Run linters and formatters",
      "permissions": {
        "tools": ["bash"],
        "bash": {
          "allowed_commands": ["npm run lint", "npm run format", "eslint", "prettier"]
        }
      }
    }
  }
}

SkillShield Integration

Scanning Claude Code Configurations

SkillShield can audit your Claude Code security configuration:

# Scan AGENTS.md for security issues
skillshield scan --type claude-config ./AGENTS.md

# Scan .claude/config.json
skillshield scan --type claude-config ./.claude/config.json

# Full project security audit
skillshield scan ./ --include claude-config

What SkillShield Checks

Check Description
Overprivileged tools Flags dangerous tools in allowed-tools
Missing deny rules Warns if critical deny rules absent
Weak restrictions Identifies permissive bash/curl rules
Secret exposure Detects potential credential access
Confirmation gaps Flags actions without confirmation

Example Output

╔════════════════════════════════════════════════════════╗
║  Claude Code Security Audit                            ║
╠════════════════════════════════════════════════════════╣
║  Config: ./.claude/config.json                         ║
║  Risk Score: 34/100 🟡 MEDIUM                          ║
╠════════════════════════════════════════════════════════╣
║  FINDINGS:                                             ║
║                                                        ║
║  ⚠️  bash tool allowed without restrictions           ║
║     Risk: Arbitrary command execution                 ║
║     Fix: Add restricted_commands or deny list         ║
║                                                        ║
║  ⚠️  Missing deny rules for credential files          ║
║     Risk: Secret exposure                             ║
║     Fix: Add .env*, .ssh/* to deny.file_access       ║
║                                                        ║
║  ✅  Git push requires confirmation                   ║
║  ✅  Write access restricted for sensitive files      ║
╚════════════════════════════════════════════════════════╝

Best Practices

1. Start Restrictive, Loosen Gradually

Don't: Start with everything allowed and try to lock down.

Do: Start with minimal permissions and add as needed.

// Start here
{
  "security": {
    "allowed_tools": ["read_file", "search", "list_dir"]
  }
}

// Add tools only when needed
{
  "security": {
    "allowed_tools": ["read_file", "search", "list_dir", "git"]
  }
}

2. Use Deny Rules for Defense in Depth

Even if you trust a tool, add deny rules:

{
  "security": {
    "allowed_tools": ["bash"],
    "deny": {
      "commands": ["sudo *", "rm -rf *", "curl * | bash"]
    }
  }
}

3. Require Confirmation for Dangerous Actions

{
  "security": {
    "require_confirmation": {
      "file_write": true,
      "git_push": true,
      "bash": true,
      "curl": true
    }
  }
}

4. Create Task-Specific Slash Commands

Instead of giving broad permissions, create scoped commands:

{
  "commands": {
    "/migrate-db": {
      "description": "Run database migrations",
      "permissions": {
        "tools": ["db", "bash"],
        "bash": {
          "allowed_commands": ["npm run migrate", "npx prisma migrate"]
        },
        "db": {
          "allowed_operations": ["ALTER", "CREATE"]
        }
      }
    }
  }
}

5. Regular Security Audits

# Weekly audit
skillshield scan --report ./claude-security-report.json

# Before adding new tools
cat AGENTS.md | skillshield scan --stdin

# CI/CD integration
skillshield scan --fail-on medium ./.claude/

Common Patterns

Pattern 1: The Secure Defaults Template

{
  "security": {
    "allowed_tools": ["read_file", "write_file", "search", "list_dir", "git"],
    "deny": {
      "file_access": [".env*", "secrets/**", ".ssh/**"],
      "commands": ["sudo *", "rm -rf *", "curl * | bash"]
    },
    "require_confirmation": {
      "file_write": true,
      "git_push": true
    }
  }
}

Pattern 2: The Database Developer

{
  "security": {
    "allowed_tools": ["read_file", "write_file", "search", "db"],
    "tools": {
      "db": {
        "allowed_operations": ["SELECT", "EXPLAIN", "DESCRIBE"],
        "forbidden_operations": ["DROP", "DELETE", "TRUNCATE"]
      }
    },
    "deny": {
      "file_access": [".env*", "database.yml", "prod-credentials.*"]
    }
  }
}

Pattern 3: The Frontend-Only Mode

{
  "security": {
    "allowed_tools": ["read_file", "write_file", "search", "bash"],
    "tools": {
      "bash": {
        "allowed_commands": ["npm *", "yarn *", "npx *", "node *"],
        "forbidden_commands": ["curl *", "wget *", "sudo *"]
      }
    },
    "deny": {
      "file_access": ["backend/**", "api/**", "server/**"]
    }
  }
}

Troubleshooting

"Claude won't use a tool I allowed"

Check: Is there a deny rule overriding it?

{
  "security": {
    "allowed_tools": ["bash"],
    "deny": {
      "commands": ["bash"]  // This overrides allowed_tools!
    }
  }
}

Fix: Remove conflicting deny rule or make it specific.

"Deny rules aren't working"

Check: Syntax and path patterns:

// Wrong
{
  "deny": {
    "file_access": ".env"  // Missing array brackets
  }
}

// Correct
{
  "deny": {
    "file_access": [".env"]
  }
}

"Slash command permissions are ignored"

Check: Command name format:

// Wrong
{
  "commands": {
    "read-only": {  // Missing leading slash
      // ...
    }
  }
}

// Correct
{
  "commands": {
    "/read-only": {
      // ...
    }
  }
}

The Bottom Line

Claude Code's permission system is powerful but requires careful configuration. The three layers — allowed-tools, deny rules, and slash commands — work together to create defense in depth.

Key takeaways:

  1. Start restrictive and add permissions as needed
  2. Use deny rules for defense in depth
  3. Create slash commands for scoped workflows
  4. Require confirmation for dangerous actions
  5. Audit regularly with SkillShield

Remember: The goal isn't to restrict Claude Code's usefulness — it's to ensure it operates within boundaries that match your security requirements.


Resources


Questions? [email protected]

Catch risky skills before they run.

SkillShield scans skills, MCP servers, and prompt-bearing tool surfaces before they reach production.

Get early access