Permissions & Sandboxing
Claude Code enforces a multi-layered security model that gates every tool invocation through permission checks, rule matching, sandbox enforcement, and destructive command detection. Nothing runs without passing through this gauntlet.
Three Permission Modes
Every Claude Code session operates in one of three permission modes, each with fundamentally different security postures:
| Mode | Behaviour | Use Case | Safety Guardrails |
|---|---|---|---|
| Default | Interactive approval -- every write operation prompts the user | Normal interactive sessions | Full |
| Plan | Read-only mode -- all write operations are blocked entirely | Code review, exploration, analysis | Full + Read-Only |
| Bypass | Auto-approve all operations, but destructive command safety stays active | Automated pipelines, CI/CD, trusted scripts | Reduced |
Bypass mode does not disable all safety. Destructive command detection (git force push to main, rm -rf /) still fires even in bypass mode. The macOS seatbelt sandbox also remains active regardless of mode.
Permission Check Flow
Every tool invocation follows a deterministic path through the permission system. The useCanUseTool() hook is the central gatekeeper:
Permission Rules
Permission rules are the mechanism for pre-authorising specific tool invocations so the user does not have to approve every action. Rules are stored as JSON in two locations:
Rule Structure
When a tool is invoked, the system iterates through deny rules first (deny takes precedence), then allow rules. Pattern matching uses glob-style wildcards. If no rule matches, the system falls through to the interactive PermissionRequest UI.
Bash Tool: 7 Security Layers
The Bash tool is the most dangerous tool in the system -- it can execute arbitrary shell commands. As a result, it has the most elaborate security stack of any tool, with seven distinct validation layers that run sequentially:
Layer 1: Mode Validation
Permission Mode Gate
The first check is the broadest: what permission mode is the session in? In Plan mode, all Bash commands that are not read-only are rejected immediately. In Bypass mode, most commands skip the interactive prompt but still pass through the remaining layers.
Layer 2: Path Validation
Every command is analysed to ensure it targets the project directory. Commands that reference paths outside the project root are flagged and may require explicit approval. This prevents accidental (or intentional) modification of system files.
Layer 3: Read-Only Validation
Commands classified as read-only are auto-approved without user interaction. The system maintains a curated allowlist of commands known to be safe:
| Category | Auto-Approved Commands |
|---|---|
| Git (read) | git log, git show, git diff, git status, git branch, git remote, git config --get |
| File inspection | cat, head, tail, less, more, file, strings, od, xxd, hexdump, wc |
| Search | grep, rg, find, fd, locate, which, type |
| Docker (read) | docker ps, docker logs, docker inspect, docker images |
| Data processing | jq, xargs (read-only), sort, uniq, awk (read-only) |
| Analysis | pyright, tsc --noEmit, ls, du, df |
Layer 4: Command Semantics
Commands that are not read-only are classified into semantic categories that determine how they are presented to the user:
| Category | Description | Examples | UI Treatment |
|---|---|---|---|
| Safe | Read-only, no side effects | cat, grep, git log |
Auto-approve |
| File-Modifying | Changes files in the project | npm install, touch, mkdir |
Prompt with diff preview |
| System-Modifying | Changes system state beyond files | brew install, apt-get, pip install |
Prompt with warning |
| Network | Makes network requests | curl, wget, ssh |
Prompt with warning |
Layer 5: Destructive Command Warning
Specific command patterns are flagged as destructive and receive an elevated warning in the UI, even in Bypass mode. These patterns are hardcoded and cannot be overridden by permission rules.
Layer 6: Git Safety
A dedicated layer for git-specific safety checks that goes beyond simple destructive command detection:
- Force push to main/master is blocked -- the system detects
git push --forcetargeting the main or master branch and refuses to execute, even in Bypass mode --no-verifyflag triggers a warning -- skipping git hooks is flagged as risky behaviour--no-gpg-signdetection -- bypassing commit signing is noted- Branch deletion safety --
git branch -Don the current branch receives a warning
The git safety layer is why Claude's system prompt explicitly says "NEVER run force push to main/master, warn the user if they request it". The prompt instruction and the code-level enforcement are dual layers of the same safety net.
Layer 7: macOS Seatbelt Sandbox
OS-Level Process Isolation
On macOS, every Bash command runs inside a sandbox-exec seatbelt profile. This is a kernel-level enforcement mechanism that restricts file system access, network connectivity, and process spawning -- regardless of what the user or permission rules say.
The seatbelt sandbox enforces these restrictions at the OS level:
| Resource | Policy | Details |
|---|---|---|
| File System (read) | Allowed | Project directory, system libraries, temp directories |
| File System (write) | Restricted | Only project directory and /tmp |
| Network (outbound) | Restricted | Allowed for npm/git operations; general outbound varies by config |
| Process spawning | Restricted | Child processes inherit sandbox restrictions |
| System calls | Filtered | Dangerous syscalls (ptrace, etc.) are blocked |
Sed Validation
The sed command receives special treatment because it can be either read-only (printing, filtering) or file-modifying (in-place editing). The system parses the sed expression to determine its intent:
The key signal is the -i flag. If present, the command is classified as file-modifying and goes through the standard approval flow. Without -i, sed only writes to stdout and is treated as read-only.
File Operation Permissions
FileEditTool (Edit)
The Edit tool has two critical preconditions that are enforced before the permission check even runs:
- Must read first: The file must have been read with the Read tool in the current conversation. The tool will error if you attempt an edit without a prior read. This prevents blind edits.
old_stringmust be unique: The string to replace must appear exactly once in the file. If it matches zero times or more than once, the edit is rejected. This prevents ambiguous edits.
FileWriteTool (Write)
The Write tool has a similar read-first requirement for existing files:
- Existing files: Must be read first. The tool will fail if you did not read the file before overwriting.
- New files: No read required. Creating a file from scratch is allowed directly.
The read-first requirement serves two purposes: it ensures Claude has seen the current state of the file before modifying it (preventing stale edits after compaction), and it creates an auditable trail showing what was in the file before the change.
Permission UI Components
When a tool invocation requires interactive approval, the system renders one of several UI components depending on context:
| Component | Trigger | User Actions |
|---|---|---|
| PermissionRequest | Standard write operation | Allow once, Allow always, Deny |
| DestructiveWarning | Destructive command detected | Allow once (no "always" option), Deny |
| BashPreview | Bash command with file changes | Allow, Deny, with command preview |
| EditDiff | File edit operation | Allow, Deny, with inline diff view |
When the user selects "Allow always", a permission rule is created and persisted to the appropriate settings.json file. Future invocations matching that rule skip the prompt entirely.
Denial Tracking
The system tracks permission denials to provide context to Claude and prevent repeated requests for the same blocked action:
- Denial count: Each denied tool+pattern combination increments a counter
- Backoff behaviour: After repeated denials of the same action, Claude is instructed to stop retrying and ask the user for guidance
- Session scoped: Denial counters reset when the session ends
- Surfaced in context: Recent denials are included in the system prompt so Claude knows what has been rejected
Enterprise MDM Controls
For enterprise deployments, Claude Code supports Mobile Device Management (MDM) style controls that override user-level settings:
Enterprise MDM rules take the highest priority in the permission chain. They are evaluated before user rules, before mode checks, and cannot be overridden by any local configuration. This is the mechanism organisations use to enforce security policies across developer machines.