Skip to content

All posts

AI

How to run Claude Code in a sandbox

Ritesh Patel

AI: How to run Claude Code in a sandbox

To run Claude Code in a sandbox, turn on its built-in Bash sandbox with /sandbox or sandbox.enabled set to true. It uses OS-level isolation to limit which files shell commands can write and which domains they reach. It is off by default and covers shell commands only (Bash, PowerShell and Monitor commands and the processes they start), not file tools, MCP servers or hooks. Use a dev container when the whole session needs a boundary.

The steps below were checked against the Claude Code sandboxing, settings and dev container docs as of 2026-10-31. Those pages name features up to v2.1.307, so run every command on Claude Code 2.1.307 or later.

Turn on the built-in sandbox

The built-in sandbox is the lightest option. It needs no Docker, and on macOS it needs no extra packages. On Linux and WSL2, it needs two packages.

  1. On Ubuntu or Debian, install the required packages. On Fedora, use dnf with the same package names.
  2. Start Claude Code in your project folder and run /sandbox. On the Mode tab, choose auto-allow or regular permissions.
  3. Run /status and check the Setting sources line to confirm the settings files that loaded.
sudo apt-get install bubblewrap socat
/sandbox

Ubuntu 24.04 needs one more check. The docs say the default AppArmor policy can block bubblewrap’s user namespaces. Run the check below first. A value of 1 means you need the AppArmor profile for /usr/bin/bwrap that the docs describe.

sysctl kernel.apparmor_restrict_unprivileged_userns

Set filesystem and network limits

By default, sandboxed commands can write to the working directory, a per-user temp directory and any directories you add. They can read most of the machine. Network access has no direct route out. Connections go through a local proxy that checks each host against network.allowedDomains, which starts empty.

Widen those defaults only for what the build needs. This example lets commands write to ~/.kube and /tmp/build, and allows two domains.

{
  "sandbox": {
    "enabled": true,
    "filesystem": {
      "allowWrite": ["~/.kube", "/tmp/build"]
    },
    "network": {
      "allowedDomains": ["github.com", "*.npmjs.org"]
    }
  }
}

Every entry widens what a command can change or send. Keep the list to the hosts your build needs. The sandboxing page notes that allowedDomains does not limit WebFetch.

To keep credential files out of reach, use the credentials block. It blocks the files and environment variables you name.

{
  "sandbox": {
    "enabled": true,
    "credentials": {
      "files": [
        { "path": "~/.aws/credentials", "mode": "deny" },
        { "path": "~/.ssh", "mode": "deny" }
      ],
      "envVars": [
        { "name": "GITHUB_TOKEN", "mode": "deny" },
        { "name": "NPM_TOKEN", "mode": "deny" }
      ]
    }
  }
}

Put these keys in the file that matches who should get them. Your user file is ~/.claude/settings.json. The shared project file, .claude/settings.json, is the one to commit for a team. .claude/settings.local.json holds personal overrides and should stay out of git. Claude Code applies the highest level that sets a key, in this order: managed settings, the command line, local, project, then user. List keys such as permissions.allow merge across files instead of replacing each other.

What the sandbox does not cover

The sandbox is narrower than most people expect. Four gaps matter most for a coding agent.

  • Built-in file and web tools. Read, Edit, Write, WebFetch and WebSearch follow permission rules. A denyRead entry does not stop the Read tool, and allowedDomains does not limit WebFetch.
  • Helper processes. Command hooks, local MCP servers, plugin monitors, LSP servers, the status line command and apiKeyHelper run with your full access.
  • Excluded commands. Anything in excludedCommands runs unsandboxed. In most sessions, commands you type at the ! shell-mode prompt also run unsandboxed.
  • Unsandboxed retries. When a command fails inside the sandbox, Claude can ask to run it unsandboxed. The allowUnsandboxedCommands setting controls that.

The practical result is that the sandbox should sit next to permission rules and hooks, not replace them. The deny rules post covers the rules that stop destructive commands, and the secrets post covers the Read deny rules for .env files.

Make the sandbox strict for a team

A developer can turn the sandbox off or allow unsandboxed retries in their own settings. To stop that, deploy the settings below through managed settings. For true/false keys like these, the managed value overrides anything in a user, project or local file.

{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false
  }
}

With failIfUnavailable set to true, Claude Code exits at startup if the sandbox can’t start, and if the sandbox fails later in a session, each sandboxed command is refused instead of running unsandboxed. Setting allowUnsandboxedCommands to false removes the unsandboxed retry.

These keys turn the sandbox on and stop fallback. They don’t fix its boundaries: list keys such as filesystem.allowWrite and network.allowedDomains merge across scopes, so a developer can still add entries. To lock network domains to the managed list, also set network.allowManagedDomainsOnly to true with your allowedDomains, and allowManagedReadPathsOnly for read paths. The docs list no managed-only lock for allowWrite. On Linux, the managed file is /etc/claude-code/managed-settings.json. A developer can run /status to see which settings sources Claude Code loaded.

Compare the sandbox options

The built-in sandbox is one of six options. The table below compares what each one isolates and what it needs. The first two run on the host without containers. The rest put Claude Code inside a container or VM.

Approach What is isolated Needs Docker Setup effort
Sandboxed Bash tool Bash, PowerShell and Monitor commands and their child processes No Minimal on macOS, low on Linux and WSL2
Sandbox runtime (beta) The whole Claude Code process, including file tools, MCP servers and hooks No Low
Dev container The full development environment Yes Medium
Custom container The full development environment Yes Medium to high
Virtual machine The full operating system No High
Cloud session The full operating system, hosted by Anthropic No None, but it needs a Claude subscription

Choose the row that matches the risk. Everyday work on your own machine fits the sandboxed Bash tool. Unattended runs with --dangerously-skip-permissions need a boundary around the whole process, so use a dev container, a VM or the sandbox runtime. The docs say the sandbox runtime is a beta research preview, so check its configuration before you rely on it.

Run the whole session in a dev container

A dev container runs Claude Code in a Docker container with your project mounted in. The commands Claude runs execute inside the container, and your edits appear in the local repository. This setup is the one to use with --dangerously-skip-permissions, because the container bounds the file tools, MCP servers and hooks as well as Bash.

  1. Add the Claude Code feature to .devcontainer/devcontainer.json, or add the features block to your existing file.
  2. Run Dev Containers: Rebuild Container from the VS Code Command Palette.
  3. Open a terminal in the container, run claude and sign in.
{
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "features": {
    "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
  }
}

The :1.0 tag pins the feature’s install script, not the Claude Code release. The feature installs the latest Claude Code, and Claude Code updates itself inside the container by default. To pin a version, install it from your Dockerfile instead, as the docs describe.

Keep sign-in and settings across rebuilds

By default the container’s home directory is discarded on rebuild, so engineers sign in again each time. To keep the sign-in and settings, mount a volume at ~/.claude and point CLAUDE_CONFIG_DIR at the same path. Replace /home/node with the home directory of your remoteUser.

"mounts": [
  "source=claude-code-config,target=/home/node/.claude,type=volume"
],
"containerEnv": {
  "CLAUDE_CONFIG_DIR": "/home/node/.claude"
}

Know what the container does not stop

Two limits apply. Claude can still change any file in the bind-mounted workspace, and those changes appear on your host. With --dangerously-skip-permissions, a malicious project can still send anything readable in the container, including the credentials in ~/.claude. Do not mount ~/.ssh or cloud credential files into the container, and prefer repository-scoped or short-lived tokens. The reference container also adds a firewall script, init-firewall.sh, that limits outbound traffic. Its NET_ADMIN and NET_RAW capabilities are optional.

Enforcing this with AIControls

The sandbox runs on each developer’s machine, so its settings are only as strong as the way they reach that machine. Deploy the strict keys through managed settings, and keep the sandbox alongside the deny rules and hooks in the risks and controls post. AIControls adds the team layer: it can route Claude Code through its gateway with per-user tokens and per-user cost and budget limits, so access and spend are set per developer rather than per laptop. For the wider policy picture, read the coding agents pillar. For runtime controls on the Kubernetes side, see the runtime page.

Frequently asked questions

Does the Claude Code sandbox cover the whole session?

No. The built-in sandbox wraps Bash commands and the processes they start. Read, Edit, Write, WebFetch and WebSearch run under permission rules instead, and MCP servers, command hooks and the status line run with your full access. To box the whole session, run Claude Code in a dev container, a VM, or the sandbox runtime, where the file tools, MCP servers and hooks sit inside the boundary too.

Is the Claude Code sandbox on by default?

No. It is off by default. Turn it on with /sandbox or by setting sandbox.enabled to true. Auto-allow mode runs sandboxed commands without a prompt, and regular permissions keeps the prompts. Both modes enforce the same filesystem and network limits, so the mode only changes how many approvals you click through.

Can Claude Code read my SSH keys inside the sandbox?

By default, yes. Sandboxed reads cover most of the machine, including ~/.ssh and ~/.aws/credentials. Add credentials.files entries with mode deny to block them. A filesystem denyRead entry does not stop the Read tool, so pair it with a Read deny rule if you need both paths closed.

Does the sandbox work on native Windows?

The built-in sandboxed Bash tool does not support native Windows. Run it inside WSL2, or use a container or VM. On Linux and WSL2, install bubblewrap and socat first. The sandbox runtime is a beta research preview and needs bubblewrap, socat and ripgrep on Linux and WSL2.

Should I use a dev container or the built-in sandbox?

Use the built-in sandbox for everyday work on your own machine, since it needs no Docker and adds no setup. Use a dev container for unattended runs with --dangerously-skip-permissions, because the container boundary covers file tools, MCP servers and hooks. A dev container does not stop a session from sending credentials it can read in ~/.claude, so keep host secrets out of the mounts.

Ritesh Patel, Founder & VP Product, Nirmata

Ritesh Patel is a founder of Nirmata and leads its products. He writes about governing AI coding agents, MCP security and Kubernetes policy as code.

LinkedIn

Govern AI agents with AIControlsControl what AI agents do, and prove it.
ShareXLinkedIn

Stay up-to-date with the latest in AI, governance, and infrastructure

Subscribe to our free monthly newsletter to get industry news, DevOps tips, and articles right to your inbox on Kyverno, containerization, Kubernetes deployment & management and more.