CLAUDE LABJP
OPUS — Claude Opus 4.7 is generally available, improving software engineering, long-running coding, and higher-resolution visionAPIKEY — You can now set an expiration on API keys in the Console, with email reminders before keys valid for 7+ days expireREFLECT — A monthly recap at Settings > Reflect shows your top topics, most active day, and peak hour (beta)M365 — The Microsoft 365 connector now supports write tools for email, calendar, and OneDrive/SharePoint filesCOWORK — Cowork expands to web and mobile, bringing Chat and Cowork into one shared home across devicesDESIGN — Claude Design, a new Anthropic Labs product, lets you co-create designs, prototypes, slides, and one-pagersOPUS — Claude Opus 4.7 is generally available, improving software engineering, long-running coding, and higher-resolution visionAPIKEY — You can now set an expiration on API keys in the Console, with email reminders before keys valid for 7+ days expireREFLECT — A monthly recap at Settings > Reflect shows your top topics, most active day, and peak hour (beta)M365 — The Microsoft 365 connector now supports write tools for email, calendar, and OneDrive/SharePoint filesCOWORK — Cowork expands to web and mobile, bringing Chat and Cowork into one shared home across devicesDESIGN — Claude Design, a new Anthropic Labs product, lets you co-create designs, prototypes, slides, and one-pagers
Articles/Claude Code
Claude Code/2026-04-13Intermediate

Claude Code Tool Permissions: Custom Allow/Deny Policies

Learn how to control Claude Code tool permissions with allowedTools, disallowedTools, and settings.json. Includes project-specific permission patterns for frontend, backend, and read-only review scenarios.

Claude Code186tool permissionssecurity12settings.jsonallowedToolsdevelopment environment

After using Claude Code for a while, most developers hit the same tension: work near production data and every rm call feels risky, but lock things down too much and the constant permission dialogs slow everything down.

Claude Code's permission system is more configurable than most people realize. You can define project-specific allow and deny lists, and commit them to your repo so the whole team uses the same settings from day one. Here's how the system works and the patterns I actually use.

Understanding Claude Code's Permission Model

Claude Code's operations fall into four categories:

  • File operations: Read, Write, Edit
  • Bash execution: Shell commands via Bash
  • Web/browser: URL fetching, browser control
  • MCP: Access to external MCP servers

By default, most operations require a permission prompt. You can skip all prompts with --dangerously-skip-permissions, but that's not appropriate anywhere near real data. The better approach is to define exactly what's allowed.

CLI Flags for One-Off Sessions

The quickest way to customize permissions is via command-line flags:

# Whitelist: only allow these tools
claude --allowedTools "Read,Write,Edit,Bash(git status),Bash(git diff)"
 
# Blacklist: allow everything except these
claude --disallowedTools "Bash(rm),Bash(sudo)"

The Bash(command) syntax lets you control individual shell commands. Allowing Bash(git status) and Bash(git diff) but nothing else gives you an effectively read-only session — Claude can inspect code but can't modify anything or run arbitrary commands.

Flags are useful for one-off sessions, but for regular development you want the settings persisted.

Project-Level settings.json

Create .claude/settings.json in your project root and Claude Code picks it up automatically when started from that directory:

// .claude/settings.json
{
  "permissions": {
    "allow": [
      "Read",
      "Write",
      "Edit",
      "Bash(git *)",
      "Bash(npm run *)",
      "Bash(npx *)",
      "Bash(echo *)",
      "Bash(cat *)",
      "Bash(ls *)",
      "Bash(grep *)",
      "Bash(find *)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(sudo *)",
      "Bash(curl *)",
      "Bash(wget *)"
    ]
  }
}

Wildcards work: Bash(git *) permits all git subcommands. Committing this file means anyone who clones the repo gets appropriate permissions without any setup.

Permission Patterns by Project Type

Frontend development — lock down network commands:

{
  "permissions": {
    "allow": [
      "Read", "Write", "Edit",
      "Bash(git *)", "Bash(npm *)", "Bash(npx *)",
      "Bash(node *)", "Bash(ts-node *)"
    ],
    "deny": [
      "Bash(curl *)", "Bash(wget *)",
      "Bash(ssh *)", "Bash(scp *)"
    ]
  }
}

Backend API development — protect database commands:

{
  "permissions": {
    "allow": [
      "Read", "Write", "Edit",
      "Bash(git *)", "Bash(go *)", "Bash(make *)",
      "Bash(docker-compose up *)", "Bash(docker-compose down)"
    ],
    "deny": [
      "Bash(psql -c DROP *)",
      "Bash(redis-cli FLUSHALL)",
      "Bash(rm -rf /var/lib/*)"
    ]
  }
}

Code review only — true read-only mode:

{
  "permissions": {
    "allow": [
      "Read",
      "Bash(git log *)", "Bash(git diff *)", "Bash(git status)",
      "Bash(cat *)", "Bash(ls *)", "Bash(grep *)"
    ],
    "deny": ["Write", "Edit", "Bash(*)"]
  }
}

Note the order in the last example: allow lists specific Bash commands, then deny blocks all remaining Bash. The allow list takes precedence over the deny list for explicitly listed commands.

Global Defaults via ~/.claude/settings.json

For operations you never want Claude Code to perform, put them in ~/.claude/settings.json:

// ~/.claude/settings.json
{
  "permissions": {
    "deny": [
      "Bash(rm -rf /)",
      "Bash(sudo rm -rf *)",
      "Bash(format *)",
      "Bash(dd if=*)"
    ]
  }
}

Priority order: project-level .claude/settings.json overrides user-level ~/.claude/settings.json, which overrides defaults. Deny rules from both levels are merged — if either file denies something, it's denied.

Checking Active Permissions

During a Claude Code session, you can inspect what's currently allowed:

/permissions

This slash command lists all currently allowed and denied tools. Useful for verifying your settings file loaded correctly.

Common Pitfalls

Wildcards are broad. Bash(git *) allows git commit -m "anything" including commit messages you might not have reviewed. If you need to prevent commits, explicitly deny Bash(git commit *).

Scripts bypass command-level deny rules. If Bash(deploy.sh) is allowed but Bash(rm -rf *) is denied, the script can still run rm -rf internally. Be conservative about which scripts you allow.

MCP permissions are separate. MCP server access is controlled through mcpServers in settings.json, not through the allowedTools Bash mechanism. If you're using MCP tools, review that section separately.

Taking 10 minutes to set up a proper settings.json for each project eliminates most of the vague anxiety that comes with using an AI agent near important files — and makes it easier to use Claude Code more aggressively where it's actually safe to do so.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-07-10
Carrying Decisions Across Compaction with PreCompact and SessionEnd Hooks
Auto-compaction does not delete your conversation. It deletes the reasons behind it. Here is a working PreCompact / SessionEnd / SessionStart hook pipeline that rescues decisions to disk and hands them to the next session, with real code and measurements.
Claude Code2026-07-09
Claude Code vs Cursor: The Definitive 2026 Comparison — Choosing the Right AI Coding Tool
A comprehensive comparison of Claude Code and Cursor across pricing, features, accuracy, and workflow. Find the AI coding tool that best fits your development style with our 2026 data-driven guide.
Claude Code2026-07-08
Auditing Your Own Code for Required Reason API Declarations with Claude Code
Required reason codes in PrivacyInfo.xcprivacy apply to your own code, not just third-party SDKs. After a wallpaper app of mine was rejected, here is the Claude Code workflow I use to scan Swift sources and match APIs to reason codes before submission.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →