The Claude Code sandbox restricts which files a bash command can write and which hosts it can reach. Turn it on. Then know where it stops: by default it can read your credential files, and it checks where a connection goes without looking at what the connection carries.

At Formal we use coding agents like Claude Code for daily work on our own laptops, and we build Formal Endpoint, the egress proxy that sits in their path. This is how to sandbox Claude Code, what the boundary leaves open, and the two layers we add on top: TLS-inspected egress and credentials kept off the machine. It applies whether Claude Code runs on a laptop, in a devcontainer or in a cloud VM.

How do you turn on the Claude Code sandbox?

The Claude Code sandbox is an OS-level boundary around the bash commands Claude Code runs. On macOS it relies on Seatbelt, the sandbox built into the operating system. On Linux and WSL2 it relies on bubblewrap and socat, so both packages need to be installed first. On native Windows there is no sandbox: commands run unsandboxed.

Type /sandbox in a Claude Code session to enable it. From then on, writes are confined to the working directory, a per-user temp directory and any directories you add. Outbound traffic can’t leave directly either. A local proxy checks every destination host against your allowed domains, and that list starts empty, so you add each host your build needs.

Anthropic’s sandboxing docs list commands that confirm the boundary holds; run them once on each OS your team uses. As of November 2026, sandbox settings change often between Claude Code releases, so check the docs against the version your developers actually run before you write a managed policy around them.

Which Claude Code sandbox mode should you use?

The sandbox has two modes. Auto-allow mode lets sandboxed bash commands run without a permission prompt, on the reasoning that the OS boundary does the restricting. Regular permissions mode keeps the sandbox and still asks before each command. Auto-allow removes most of the prompting in an interactive session; regular mode keeps a person approving every step.

Auto-allow isn’t the same as skipping permissions: the boundary still applies to every command it runs. Approving commands by hand isn’t airtight either: allowing a handful of bash commands can amount to allowing any command, because build and test tools run code the agent can edit. Either way, the mode only changes who approves a command. It doesn’t change what an approved command can reach.

What doesn’t the Claude Code sandbox cover?

Anthropic says it plainly: “Sandboxing reduces risk but is not a complete isolation boundary.” Here is what stays open with default settings, according to Anthropic’s docs as of November 2026:

  • Reads of credential files. Sandboxed commands can read most of the machine, ~/.ssh and ~/.aws/credentials included, until you add denyRead rules or the credentials settings.
  • The built-in tools. Read, Edit, Write, WebFetch and WebSearch run outside the sandbox and follow permission rules instead. allowedDomains doesn’t apply to WebFetch.
  • Excluded commands. Anything listed in excludedCommands runs unsandboxed.
  • The retry escape hatch. When a command fails inside the sandbox, Claude may run it again with dangerouslyDisableSandbox. Strict sandbox mode removes that option.
  • TLS. In Anthropic’s words, “By default the built-in proxy does not terminate or inspect TLS.” The proxy sees a hostname, never the request.

The last gap matters most for exfiltration. Anthropic’s docs warn that a broad domain such as github.com can become a path for data to leave, and that domain fronting can reach hosts that aren’t on the list. Network isolation by hostname tells you where a connection goes. It can’t tell a clone from a push, or a status check from an upload of your credentials.

Anthropic’s recommended fix is a custom proxy that terminates TLS and inspects the traffic, wired in through sandbox.network.httpProxyPort or socksProxyPort. That proxy is the layer we build, and the next three sections show how we use it with Claude Code.

Claude Code devcontainer, Docker or VM: which sandboxing option fits?

The built-in sandbox isn’t the only way to contain Claude Code. A devcontainer, your own Docker container or a VM moves the boundary further out: the agent sees only the mounts and files you give it, and a VM adds a separate kernel between the agent and your laptop. What none of them does on its own is judge the requests the agent sends.

OptionFilesystem boundaryNetwork controlCredentials inside
Built-in sandboxWrites limited to the project and temp directories; most reads allowed by defaultHost allowlist through a local proxy, no TLS inspection by defaultWhatever the user can read, unless denied
Anthropic’s devcontainerThe container plus the mounted workspaceFirewall script that allows a fixed set of IPsWhatever you pass into the container
Your own Docker containerWhatever you mountOpen unless you add rulesWhatever you pass in
VM or cloud agentThe VM’s own diskWhatever the VM’s network allowsWhatever you provision on it

We took the devcontainer firewall apart when we wrote about routing Claude Code through a proxy. It resolves the allowed hostnames to IPs when the container starts and leaves port 22 open, so an allowed IP can still carry data out. A Claude Code Docker sandbox has the same question to answer: once a connection is allowed, who reads it?

How do you inspect what sandboxed commands send?

Formal Endpoint runs on the machine where Claude Code runs. In Transparent Mode, on macOS and Linux, it captures TCP connections inside the operating system’s networking stack, so neither Claude Code nor its sandbox needs proxy settings. Interception happens below the application: the CLI and anything its sandboxed shell starts fall under the same rule.

When a rule matches, the Endpoint terminates TLS with certificates from the Formal local CA, classifies the protocol and evaluates your policies on the request itself. Each network rule is a CEL expression with one condition per stage: pre_tcp decides whether to divert the connection (macOS only), pre_tls whether to terminate its TLS, and post_tls whether to inspect it once Formal knows the protocol.

The agent flags, process.is_agent and process.has_agent_ancestor, use code-signed process identity on macOS. Claude Code is identified by its signing Team ID, Q6L2SF6YDW, and a child process such as git or curl inherits the match through its ancestor. This rule from the network rules docs diverts traffic from known agents and their children, then intercepts their MCP and LLM calls:

{
  "condition": {
    "pre_tcp": process.is_agent || process.has_agent_ancestor,
    "pre_tls": true,
    "post_tls": technology in ["mcp", "llm"]
  }
}

The post_tls list accepts other classified protocols too, including http, aws and ssh, so the same pattern extends to ordinary API calls. Connections that no rule selects go straight through, with no log entry and no policy check. On Linux, the agent flags match process names rather than signatures. Windows has no Transparent Mode: there the Endpoint only offers local listeners through formal connect.

Will sandboxed commands trust the inspected TLS?

Only if each client trusts the Formal CA. formal ca trust adds it to the OS trust store, which browsers and Go programs read, but Node.js and most Python HTTP clients carry their own roots. Unless runtime_ca_env is set to none, the Endpoint writes NODE_EXTRA_CA_CERTS, SSL_CERT_FILE and REQUESTS_CA_BUNDLE into Claude Code’s ~/.claude/settings.json.

Setting runtime_ca_env = "all" adds variables for the AWS CLI, pip, git, cargo and gRPC to the login session. A client that still rejects the certificate should be left out of pre_tls, or it fails with CA errors instead of being inspected. The details are under Runtime TLS trust in the Endpoint docs.

How do you keep credentials out of the sandbox?

A denyRead rule stops a command from opening ~/.ssh, but it can’t hide a key the code needs while it runs. Claude Code sees the environment variables of the terminal it was started from, and the sandbox inherits them. A .env file in the project is just as readable. If the key is on the machine, a command can send it somewhere.

Credential injection takes the key off the machine. The real key sits on a Formal Connector, stored as a Native User. The Endpoint sends the requests a network rule selects to that Connector, carrying the developer’s Formal identity, and that Connector attaches the credential (an Authorization: Bearer header, for instance) on the way upstream. Clients keep calling the real hostname, holding no key of their own.

The Stripe walkthrough shows the result: Stripe gets the real key, the laptop never does, and Rego scopes one group to read-only Stripe endpoints. Our proxy post builds the same setup for the Anthropic API key, Terraform included. Formal Endpoint applies the pattern to any API that Claude Code or its code calls.

How do you block risky actions the sandbox allows?

Allowing github.com allows clones and pushes alike. Git reaches GitHub over SSH, over SSH on port 443 at ssh.github.com, and over HTTPS, so a control on one transport is bypassed by changing the remote URL. On macOS, the guide to block agent git pushes starts with one network rule that selects git traffic from any known agent or its children:

{
  "condition": {
    "pre_tcp": process.has_agent_ancestor,
    "pre_tls": hostname in ["github.com", "ssh.github.com"],
    "post_tls": technology in ["http", "ssh"]
  }
}

A Rego policy then blocks git-receive-pack, the server command behind every push, for the repositories you list: in the SSH command for SSH pushes and in the POST path for HTTPS ones. Clones and fetches use git-upload-pack and still work. A push from the developer’s own terminal never matches the rule, and an mfa action can replace the block to pause the agent until the developer confirms.

The same approach covers other actions an allowlist can’t see, such as tool calls whose arguments carry a GitHub token, or uploads to Anthropic’s Files API. Our Claude Code security page lists the documented policies for Claude Code. Create each policy in Dry-run first and set it to Active after reviewing what it matches.

What setup do we recommend for Claude Code?

Layer the controls so each one covers a gap the others leave, in interactive sessions and agentic workflows alike:

  • Sandbox. Turn on the Claude Code sandbox, deny reads of credential files, and enable strict mode so failed commands can’t retry outside it.
  • Allowed domains. Keep the list short, knowing every entry is still a way out.
  • Egress. Add TLS-inspected egress with network rules matched to Claude Code and its children.
  • Credentials. Inject keys at a Connector instead of storing them on the machine.
  • Actions. Block what you can’t undo, starting with agent pushes to sensitive repositories.

Cursor’s security team follows the same principle for its Cloud Agents: isolated environments with tightly restricted outbound connections, plus scoped Formal policies on the data those agents reach. Formal secures thousands of resources across 10+ technologies at Cursor and handles 40M+ logs and 600K+ sessions per week. The full story is in the Cursor case study.

“Without Formal, we couldn’t have agents with access to sensitive data. With Formal, because we are able to inspect all traffic and enforce controls, we are able to provide a safe environment for the agents to get the job done.”

— Travis McPeak, Head of Security @ Cursor

Frequently asked questions

Should I run Claude Code in a sandbox?

Yes. The Claude Code sandbox takes one command to enable in a session and limits what a bash command can write and which hosts it can reach. Treat it as the first layer rather than the whole design: it reads most of the machine by default and doesn’t inspect TLS, so pair it with denyRead rules, an egress layer that reads requests, and credentials kept off the machine.

Does the Claude Code sandbox work on Windows?

Not natively. As of November 2026, Anthropic’s sandbox runs on macOS, Linux and WSL2, and commands on native Windows run unsandboxed, so run Claude Code inside WSL2 to get the bubblewrap sandbox. Formal Endpoint has a similar split: interception and network rules need macOS or Linux, and on Windows the Endpoint offers only local listeners through formal connect.

Does the Claude Code sandbox inspect HTTPS traffic?

Not by default. The built-in proxy compares the destination hostname with your allowed domains but doesn’t terminate TLS, so it never sees the method, path or body of a request. Anthropic suggests pointing sandbox.network.httpProxyPort at a proxy that does. Formal Endpoint terminates TLS with its local CA in Transparent Mode, with no proxy settings to configure in Claude Code.

Can Claude Code still read my credentials inside the sandbox?

By default, yes. Sandboxed commands can read most of the machine, including ~/.ssh and ~/.aws/credentials, until you add denyRead rules or the credentials settings. Environment variables and .env files in the project stay readable either way. The sturdier pattern is credential injection: the key lives on a Formal Connector and joins the request only after it has left the machine.

Is a Claude Code devcontainer safer than the built-in sandbox?

It’s a different boundary, not a stricter one by default. A Claude Code devcontainer confines the agent to the container and its mounted workspace, which protects the rest of your filesystem. Anthropic’s template firewall allows a fixed set of IPs, though, and anything you pass into the container is readable. Whichever you choose, the network still needs a layer that reads the requests.

Can Claude Code escape its sandbox?

It doesn’t need an exploit to run outside it. When a command fails inside the sandbox, Claude may retry it with dangerouslyDisableSandbox, and commands in excludedCommands always run unsandboxed. Enable strict sandbox mode to remove the retry and keep the exclusion list short. Anthropic also says the sandbox isn’t a complete isolation boundary, so controls outside the agent still matter.

How do I sandbox Claude Code in CI or cloud agents?

Autonomous runs have nobody to answer a prompt, so contain them in a VM or container with the egress layer inside. Formal’s headless Linux package runs as a systemd user service. In Cursor and Devin cloud agents, the Endpoint signs in with OIDC, runs with transparent_proxy.enforce = true and fail = "closed", and a policy blocks pull request auto-merge. Kubernetes Pods and Amazon ECS tasks run it as a sidecar. Our own setup is in Giving Cloud Agents Production Access with OIDC.

Formal Endpoint adds the egress layer the sandbox leaves out, on laptops, VMs and Kubernetes. See how Formal Endpoint works, or talk to us about your Claude Code rollout.

Get a demo ›