The Navigator · 10 min mission

Permissions, Sandboxing & Staying Safe

Run Claude with exactly the autonomy you intend — no more, no less.

securitypermissionsconfigurationFact-checked 2026-06-13
On this page

An agent that can edit your files and run shell commands is exactly as useful — and as dangerous — as the boundaries you put around it. Claude Code's permission system is where you draw those boundaries. Get it right and Claude races through a refactor without nagging you for approval on every safe command. Get it wrong and you either drown in prompts or hand a language model an unsupervised shell.

The good news: the defaults are deliberately cautious, and the controls are precise. This guide takes you from the prompts you see on day one to the allow/deny rules, permission modes, and OS-level sandbox you'll use to run Claude with exactly the autonomy you intend.

The tiered permission model

Claude Code does not treat every action the same. The official docs describe a tiered system, and understanding the tiers explains every prompt you ever see. Read-only operations — file reads, Grep, Glob, and a built-in set of shell commands like ls, cat, pwd, grep, and read-only git — run with no prompt at all, in every mode. Bash commands that can change your system require approval; when you pick "Yes, don't ask again," the allowance is saved permanently for that project and command. File modifications (Edit/Write) also require approval, but "don't ask again" only lasts until the session ends.

That last detail is the whole philosophy in miniature: reading is safe and never gated, running commands is a deliberate per-command grant, and editing files is trusted only for the current session unless you say otherwise.

Allow, ask, deny — and deny always wins

Three rule lists govern what Claude can do without stopping to ask:

  • Allow rules let Claude use a tool with no manual approval.
  • Ask rules force a confirmation prompt every time Claude tries that tool.
  • Deny rules block the tool outright — Claude cannot use it at all.

The single most important fact about these lists is their evaluation order: deny, then ask, then allow. The first match in that order decides the outcome, and specificity does not change the order. So a broad deny beats a narrow allow every time, and an ask rule still prompts you even when a more specific allow rule also matches the same call. When you want a guarantee, you write it as a deny — because nothing downstream can override it.

This holds across settings files too. If your user settings allow something and your project settings deny it, the deny wins. The reverse is equally true: a user-level deny blocks a project-level allow, because deny rules from any scope are evaluated before allow rules from any scope.

RuleWhat it matches
BashEvery Bash command (as a deny rule, removes the tool entirely)
Bash(npm run build)The exact command npm run build
Bash(npm run test:*)Any command starting with npm run test (:* is a trailing wildcard)
Bash(git push *)Any git push … command — the space before * enforces a word boundary
Read(./.env)Reading .env in the current directory
Read(./secrets/**)Reading anything under secrets/ (gitignore-style ** spans directories)
Edit(/src/**/*.ts)Editing any .ts file under the project root src/
WebFetch(domain:example.com)Fetching from the host example.com
mcp__github__get_*Every get_ tool on the github MCP server
Tool-specifier syntax. Rules take the form `Tool` or `Tool(specifier)`. A bare tool name matches every use of that tool.

Permission modes change the default posture

Rules decide which calls are allowed; permission modes decide the overall stance toward prompting. You set the starting mode with the defaultMode key in any settings file, and you can switch modes mid-session. Four modes matter most:

  • default — standard behavior. Claude prompts on first use of each tool, and your allow/ask/deny rules apply as written. This is where you should live most of the time.
  • acceptEdits — auto-accepts file edits and a fixed set of filesystem Bash commands (mkdir, touch, mv, cp, rm, sed, and similar) for paths in the working directory or your additional directories. Other Bash commands and out-of-scope paths still prompt. Great for a focused editing session where you trust the plan.
  • plan — Plan Mode. Claude reads files and runs read-only shell commands to explore, but does not edit your source files. Use it to let Claude investigate and propose an approach before it changes anything.
  • bypassPermissions — skips permission prompts entirely. This is the loaded gun of the four; see the warning below.

Two newer modes also exist: auto (a research-preview mode that auto-approves calls with a background classifier checking they match your request) and dontAsk (auto-denies anything not explicitly pre-approved). Reach for the four above first.

Trace a tool call through your rules

Permission simulator

Pick an action and a permission mode. The engine runs the same deny → ask → allow precedence Claude Code uses and reveals the verdict — with the one rule that fired.

Action

What is Claude about to do?

Permission mode

How freely is Claude allowed to act?

permission check
defaultMode
Edit config.ts
mode = default
ASKPauses for your approval

Editing a file is a modification — default mode prompts you to approve it first.

ask · Edit (first use)
Pick a command and a set of allow/ask/deny rules, then watch the harness evaluate them in order — deny first, then ask, then allow. The fastest way to feel why deny always wins.

Settings precedence: enterprise beats everything

Permission rules can live in several files, and when they disagree, precedence decides. From highest authority to lowest:

  1. Managed (enterprise) settings — deployed by your organization via MDM, a managed-settings file, or server-managed settings. These cannot be overridden by anything, not even command-line flags.
  2. Command-line arguments — temporary overrides for one session (--allowedTools, --disallowedTools, --add-dir).
  3. Local project settings.claude/settings.local.json, gitignored, your personal per-project overrides.
  4. Shared project settings.claude/settings.json, committed to git and shared with your team.
  5. User settings~/.claude/settings.json, your defaults across every project.

Two subtleties make this work in practice. First, permission rules merge across scopes rather than fully replacing each other — your deny lists from every level stack up. Second, the deny-first rule cuts across the whole stack: a managed deny cannot be loosened by a project allow or a --allowedTools flag. That is exactly what lets a security team set guardrails that individual developers cannot accidentally undo. Audit what is actually in effect any time with /permissions.

inspect and tighten with /permissions
… scroll to run this session
The /permissions view lists every rule and the settings file it came from. Here a deny rule on .env wins over a broad allow — exactly as the precedence model promises.

The sandbox: OS-level isolation for Bash

Permission rules are checked by the harness before a command runs, based on the command string. But a clever or compromised command can do more than its name suggests. The sandbox closes that gap by enforcing boundaries at the operating-system level, on the running process and all of its child processes — so the limits hold regardless of what the model decided to run.

You enable it with the /sandbox command, which opens a panel to pick a mode and review the resolved configuration. It runs on macOS (using the built-in Seatbelt framework), Linux, and WSL2 (using bubblewrap); native Windows is not supported. The sandbox enforces two kinds of isolation:

  • Filesystem isolation — by default, sandboxed commands can write only to the working directory and the session temp directory, while reading most of the computer. You widen or tighten this with sandbox.filesystem.allowWrite, denyRead, and allowRead. (Note the default read policy still allows reading ~/.aws/credentials and ~/.ssh/ — add them to denyRead if that matters to you.)
  • Network isolation — no domains are pre-allowed. The first time a command needs a new domain, Claude Code prompts; pre-approve hosts with sandbox.allowedDomains.

The payoff is fewer prompts with a real boundary. In the sandbox's auto-allow mode (the default autoAllowBashIfSandboxed: true), sandboxed Bash commands run without prompting because the sandbox itself contains them — yet explicit deny rules, content-scoped ask rules like Bash(git push *), and dangerous rm targets still stop to ask. Permissions and the sandbox are complementary layers: use deny rules to stop Claude from attempting something, and the sandbox to stop a command from reaching outside its boundary even if a prompt injection slips past Claude's judgment.

Two patterns for an unattended run

Fragile

--dangerously-skip-permissions (bypassPermissions) on your real laptop, in your home directory, with your SSH keys and cloud credentials one cat away.

One prompt-injected README or poisoned dependency and there is nothing between the model and your filesystem. Speed, zero safety.

Safe

Run inside a container or VM, enable the sandbox with sandbox.enabled: true, scope writes to the project, set denyRead on credential directories, and allow only the domains the task needs.

Claude works autonomously inside a boundary the OS enforces — and failIfUnavailable: true refuses to start if the sandbox cannot.

Knowledge check

Your project settings include `allow: ["Bash(git push *)"]`, but your managed (enterprise) settings include `deny: ["Bash(git push *)"]`. Claude tries to run `git push origin main`. What happens?

A safe starting posture

Pull it together into habits. Stay in default mode for everyday work and let your allowlist grow from the commands you actually approve. Reach for plan mode when you want Claude to investigate before it touches anything, and acceptEdits for a trusted editing sprint. Write deny rules for the things that must never happen — reading .env and secret directories, pushing to protected branches, running raw network tools — because deny is the only guarantee the system offers. Reserve bypassPermissions for throwaway containers, never your real machine.

And when you want genuine autonomy, combine the layers: a container for blast-radius, the sandbox for OS-enforced boundaries, deny rules for the model's intentions, and /permissions to audit it all. Permissions shape what Claude tries; the sandbox limits what any command can reach; precedence lets your organization set rules nobody can quietly undo. That is how you give an agent real power without handing it the keys to everything.

Reach the end and this star joins your charted sky.