What Are the Best allowedTools Configurations for Secure Claude Workflows?
The single highest-leverage security control in Claude Code is the permissions block in settings.json. Here is how to configure deny, ask, and allow rules across the four settings scopes, choose the right permission mode, and lock down shell access without drowning in approval prompts — with concrete 2026 configuration examples and the statistics that explain why this matters now.
What Are the Best allowedTools Configurations for Secure Claude Workflows?
The best allowedTools configuration for Claude Code is a layered deny-ask-allow ruleset committed to a shared .claude/settings.json, with default or acceptEdits as the permission mode, secrets explicitly denied, destructive commands routed through ask, and CI pipelines locked to dontAsk. The goal is not to eliminate autonomy — it is to give Claude Code exactly the permissions it needs to be productive and nothing more, so that when something goes wrong, the blast radius is a single file, not your production infrastructure.
Claude Code runs with the same filesystem and shell permissions as the developer who invokes it. It can read any file your user can read, execute arbitrary bash commands, modify multiple files simultaneously, and reach external services through the Model Context Protocol. That power is what makes it productive. It is also what makes an unconfigured deployment a serious security exposure. The allowedTools system — the allow, deny, and ask arrays inside the permissions block of settings.json — is the primary mechanism for controlling that exposure.
Why Permission Configuration Matters in 2026
The threat model for AI coding agents shifted in 2026. It is no longer just "bad generated code" — it is arbitrary code execution by an agent that operates in your terminal with your credentials.
The data tells the story:
- 87% of AI agent pull requests contained vulnerabilities, according to a March 2026 report by DryRun Security
- Opsera's "AI Coding Impact 2026 Benchmark," tracking 250,000+ developers, found a 15 to 18% increase in security vulnerabilities when AI coding agents were introduced
- Only 10% of AI-generated code is both functional and secure, per a joint March 2026 study by Endor Labs, Carnegie Mellon University, Columbia, and Johns Hopkins
- AI coding agent security incidents are now weekly occurrences, as reported by Thoughtworks at QCon in March 2026
- Check Point Research disclosed CVE-2025-59536 (CVSS 8.7) in early 2026 — a remote code execution vulnerability in Claude Code triggered by malicious project configuration files before any trust dialog appears
The compounding factor is approval fatigue. Anthropic reported in June 2026 that users approve 93% of all permission prompts. When nearly every prompt gets a reflexive "yes," the prompt itself is not a security control — it is a ceremony. Nearly half of active Claude CLI users (49.5%) manually created a broad Bash allow-rule to suppress prompts, 43% allowed broad interpreter access like Bash(python:*), and 5% gave Claude outright blanket shell access with Bash(*). The permissions system exists to make the right choice the easy one, so you are not relying on willpower at 2 AM.
The Settings Hierarchy: Four Scopes That Merge
Claude Code reads settings from multiple settings.json files and merges permission rules additively across them. The scopes, from highest authority to lowest:
- Managed settings — enterprise policy delivered from the claude.ai console. Highest priority, the right place for organization-wide guardrails that individual developers cannot override.
- User settings (
~/.claude/settings.json) — personal defaults applied across every project on your machine. Good for commit conventions and preferred tooling. - Shared project settings (
.claude/settings.json) — committed to git, shared with the entire team. This is where baseline safety rails live. - Local project settings (
.claude/settings.local.json) — git-ignored personal overrides for workflow quirks you do not want to push.
The critical rule: a deny rule defined at any scope stays in force and cannot be loosened by a less authoritative scope. If enterprise managed settings deny Read(*.env*), no project-level allow rule can unblock it. This merge behavior means you can layer organizational policy, team conventions, and personal preferences without worrying that a junior developer's local settings file accidentally removes a security guardrail.
The Three Rule Types: Deny, Ask, Allow
Inside the permissions object, three arrays control every tool call Claude Code makes:
deny— evaluated first. If a tool call matches a deny rule, it is blocked outright with no prompt. A bare tool name likeBashremoves the tool from Claude's context entirely, so Claude never even sees it. A scoped rule likeBash(rm -rf *)leaves the tool available but blocks matching calls. Deny rules survive evenbypassPermissionsmode, which is why they are the backbone of any secure configuration.ask— evaluated second. If matched, Claude pauses and forces a manual approval prompt. Use this for operations that are sometimes legitimate but dangerous enough to warrant a checkpoint —git push,npm install, creating new files withWrite.allow— evaluated third. If matched, the tool call is auto-approved without interruption. This is where you put the commands Claude needs to run repeatedly during normal development —npm test,npm run lint,git status,git diff.
The evaluation order matters: deny wins over allow. If you have allow: ["Bash"] but also deny: ["Bash(rm:*)"], the rm command is blocked. This precedence is the mechanism that lets you grant broad access while still carving out exceptions for dangerous operations.
Pattern Syntax for Scoped Rules
Scoped rules use glob-style matching inside parentheses. Bash(npm test) matches that exact command. Bash(npm run *) matches any npm-run invocation. Read(src/**) matches any file under src/. Edit(src/**) scopes edits to a specific directory. The specificity is what makes the system practical — you can grant Claude autonomy within src/ while requiring approval for anything in infrastructure/ or migrations/.
The Six Permission Modes
Claude Code supports six permission modes that set the default autonomy level for the session. Choose based on the sensitivity of the environment:
default— asks before any tool that could modify the system or hit the network. Reads are free. This is the safe starting point and what every new install gives you. You will see a lot of approval prompts until you build up an allow list.acceptEdits— auto-approves file reads, standard edits, and common non-destructive filesystem commands likemkdir,touch,cp, andmv. A good middle ground for daily development once you trust your deny rules.plan— read-only exploration. Claude can read the codebase and run read-only shell commands to gather context, but is blocked from making any edits until you approve a formal plan. Use this when working in unfamiliar or regulated repositories.auto— the default on Pro, Max, and Team plans as of August 2026. Auto-approves most tool calls but routes them through a background AI safety classifier that intercepts risky commands. A reasonable default for experienced teams with good deny rules.bypassPermissions— skips nearly all prompts, activated via--dangerously-skip-permissions. Still enforces prompts for protected paths like.git/and.claude/and respects explicitdenyrules. Only for isolated VMs or Docker containers where the blast radius is zero.dontAsk— auto-denies all tool calls unless they explicitly match anallowrule. The correct mode for unattended CI/CD pipelines, where a hung prompt waiting for human input is a pipeline failure.
A Production-Grade Configuration
Here is a battle-tested .claude/settings.json for a team working on a TypeScript project, balancing productivity with security:
defaultMode: "acceptEdits"— auto-approve edits but prompt for network and destructive operations- Allow:
Bash(npm test),Bash(npm run lint),Bash(npm run typecheck),Bash(git status),Bash(git diff:*),Bash(git log:*),Read(src/**),Read(docs/**),Edit(src/**) - Deny:
Read(*.env*),Read(*.pem),Read(*.key),Read(./secrets/**),Read(~/.ssh/**),Read(~/.aws/**),Bash(rm -rf *),Bash(npm publish),Bash(curl *),Bash(wget *),Bash(sudo:*),Bash(git push --force*),Bash(git reset --hard*) - Ask:
Bash(git push:*),Bash(npm install:*),Bash(docker:*),Bash(kubectl:*),Bash(terraform:*),Write(*)
The logic: reads and edits within src/ are free, so Claude can work without interruption. Destructive shell commands and secret file access are denied outright, so they are impossible regardless of context. Infrastructure and deployment commands require explicit approval, so no accidental git push --force to main. New file creation (Write) goes through ask because creating new files is higher-risk than editing existing ones — a new file can introduce an entirely new attack surface that no reviewer is expecting.
Best Practices for Enterprise Teams
Commit shared guardrails to git. Store baseline deny and ask rules in .claude/settings.json and check it in. Every teammate inherits the safety rails automatically, while still being able to add personal overrides in their git-ignored .local.json.
Fail closed in CI. Run Claude Code with --permission-mode dontAsk in CI pipelines so unapproved actions are rejected automatically rather than hanging the pipeline waiting for input that will never come.
Deny secrets by default. Explicitly list .env, .pem, .key, .ssh/, .aws/, and any other credential paths under deny. A prompt injection that tries to read your AWS credentials should fail before it starts, not trigger a prompt you might approve reflexively.
Use plan mode for unfamiliar codebases. When a new hire or contractor joins, start them in plan mode so Claude explores the architecture without the ability to make changes until the plan is reviewed. This prevents an agent from "helpfully" refactoring code it does not yet understand.
Audit quarterly. Read your settings.json cold, the way a new teammate would. Ask whether each entry still earns its slot, whether the deny list still catches what you would not want the model to do, and whether anything is a leftover from a project you are no longer running. Permissions are not set-and-forget — they are how you tell Claude what is normal, and normal changes as the codebase does.
Lock down MCP servers. MCP servers run with your full local permissions. Treat mcp add like installing a CLI tool — only add servers from sources you trust, and read the config they write before running anything sensitive. For sensitive environments, use allowManagedMcpServersOnly to restrict MCP servers to a managed catalog that is easier to audit than ad hoc project-scoped tool servers.
The Bottom Line
The difference between a secure Claude Code deployment and a dangerous one is not the model — it is the configuration. A well-tuned allowedTools setup turns a disruptive approval loop into a smooth workflow where Claude can work autonomously within safe boundaries, destructive commands are impossible, and secrets are invisible. The investment is thirty minutes of configuration that compounds across every future session. The alternative is hoping that a 93% approval rate on prompts will catch the one command that matters.
If you want help auditing your Claude Code permissions, setting up enterprise-managed settings, or configuring a secure CI pipeline with dontAsk mode, ishchuk.eu offers AI automation consulting for engineering teams. We can ship a production-ready permission configuration in days, not months.
Frequently asked questions
- What is allowedTools in Claude Code and how does it work?
- allowedTools is the permissions system inside Claude Code's settings.json that controls which tool calls the agent can make automatically, which require approval, and which are blocked entirely. It uses three rule arrays inside a permissions object: deny rules are evaluated first and block matching calls outright, ask rules force a manual approval prompt, and allow rules auto-approve matching calls without interruption. Rules can be scoped to specific patterns using glob syntax like Bash(npm test) or Read(src/**), and they merge across four settings scopes from enterprise policy down to local project files.
- How do I configure Claude Code permissions to prevent dangerous shell commands?
- Add destructive commands to the deny array in your .claude/settings.json file. For example, deny Bash(rm -rf *) blocks recursive deletes, Bash(sudo:*) blocks privilege escalation, Bash(git push --force*) blocks force pushes, and Bash(npm publish) blocks accidental package publishes. Deny rules are evaluated first and cannot be overridden by allow rules or bypassPermissions mode, making them the strongest security control. Also deny Read access to secret files like .env, .pem, and .key files to prevent credential exposure through prompt injection.
- What is the difference between Claude Code permission modes default, acceptEdits, plan, and bypassPermissions?
- Default mode asks before any modifying or network tool call and is the safest starting point. AcceptEdits auto-approves file edits and common non-destructive filesystem commands while still prompting for network and destructive operations. Plan mode is read-only exploration where Claude can read code and run read-only commands but cannot make edits until a formal plan is approved. BypassPermissions skips nearly all prompts and should only be used in isolated VMs or Docker containers where the blast radius is zero, as it leaves the agent nearly unrestricted except for protected paths and explicit deny rules.
- Should I use bypassPermissions mode with Claude Code?
- BypassPermissions mode, activated via the --dangerously-skip-permissions flag, should only be used in fully isolated environments like disposable VMs or Docker containers. It skips nearly all approval prompts, leaving the agent free to execute arbitrary shell commands, modify files, and make network requests without oversight. While it still enforces deny rules and prompts for protected paths like .git and .claude, the risk of unrestricted shell execution in a non-isolated environment includes data exfiltration, credential exposure, and lateral movement. Treat bypassPermissions like production database write access: logged, audited, and restricted to specific roles.
- How do I run Claude Code securely in CI/CD pipelines?
- Use the dontAsk permission mode in CI pipelines, which auto-denies all tool calls unless they explicitly match an allow rule in your settings.json. This prevents the pipeline from hanging on an approval prompt that no human will answer, and ensures only pre-approved commands execute. Configure your allow list with specific safe commands like Bash(npm test) and Bash(npm run lint), deny all secret file access and destructive commands, and never use bypassPermissions in CI. Also set allowManagedMcpServersOnly to restrict MCP servers to a managed, audited catalog rather than ad hoc project-scoped tools.