Agent IndexAgent Permissions Index

Guides / Claude Code

How to add deny rules in Claude Code (settings.json examples)

Add a permissions.deny array to .claude/settings.json (or settings.local.json). Each entry is a rule like Read(./.env) or Bash(git push *). Claude Code checks deny before ask and allow, so a matching deny blocks the call even if an allow rule also matches.

Stats from the 2026-10-20 snapshot of public GitHub configs (methodology). Behavior checked against the official docs linked below.

Minimal example

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Edit(./.claude/**)",
      "Write(./.claude/**)",
      "Bash(git push *)",
      "Bash(rm -rf *)"
    ]
  }
}

How precedence works

Rules are evaluated deny → ask → allow, and the first match wins regardless of how specific the rule is. A broad deny like Bash(aws *) blocks Bash(aws s3 ls) even if that is explicitly allowed. A bare tool name in deny (for example WebFetch) removes the tool entirely. Deny rules apply in every permission mode, including bypassPermissions.

Which rules to deny first

Secrets (Read(./.env), Read(./.env.*), Read(./secrets/**)), the settings directory (Edit(./.claude/**), Write(./.claude/**)), so the agent can't rewrite its own deny list, and irreversible commands such as git push and rm -rf. Use ask instead of deny for commands you want to approve case by case.

What public configs do

Of 4,831 unique public Claude Code configs with a permissions block, 85.6% have no deny rules. 24% allow a wildcard interpreter and 12.5% allow curl or wget to any URL, which are the cases where deny rules matter most.

What existing deny rules cover

Of the 694 unique configs that have deny rules: .env files 339 (48.8%), secrets / credentials paths 152 (21.9%), .claude settings 31 (4.5%), git push 292 (42.1%), rm (incl. rm -rf) 331 (47.7%). Only 5 cover all five. As a share of all 4,831 configs with permissions, only 7% deny .env.

Rule syntax note

Current docs write wildcards with a space, e.g. Bash(npm run *). Many existing configs use the older colon form, e.g. Bash(npm run:*).

FAQ

Do deny rules work in bypassPermissions mode?

Yes. Per the Claude Code docs, deny rules block in every mode, including bypassPermissions.

Where should team-wide deny rules go?

In .claude/settings.json committed to the repo, or in managed settings if your organization deploys them. Personal additions go in .claude/settings.local.json.

Sources