31 tools· updated sep 2026

Claude Code Sandbox: Check File and Network Boundaries Before a Run

Marek.

  • claude-code
  • agent-security
  • agent-ops

A protected file stayed untouched in the sandbox fixture prepared for this article. No file appeared outside the working directory either. That sounds encouraging until you read the first result: the allowed command never started. Missing socat. Nothing ran, so nothing changed.

That is where I would start with Claude Code sandboxing. Get one ordinary operation working before trusting a blocked one. A broken environment can hand you the result you wanted without any of the protection.

I have seen a guard fail quietly outside the sandbox too. I run a guard hook in front of risky shell commands. On 22 September 2026 it took 13.4 seconds and 22.9 seconds to answer. Its timeout was 10. Both times the command ran and the hook never got to ask. A command hook that times out does not block the call. On 5 October I moved the timeout to 60 seconds. Hook timeouts.

  • The first result: an allowed write failed before isolation could be checked.
  • The platform matters: WSL2 is supported. That says nothing about native Windows.
  • Two separate boundaries: file access needs its own control. So does network access.
  • Exceptions need a comparison: opening one path should leave protected paths closed.
  • The scope ends somewhere: shell containment does not cover every tool an agent can call.

The broader workflow is in the Claude Code review. Here I want to settle a smaller question: when a command fails, did the sandbox stop it, or was the command unable to run at all?

The test stopped before the interesting part

The attempt on 3 October 2026 used Anthropic's standalone sandbox-runtime 0.0.78 on Ubuntu 26.04 under WSL2. The first probe was an allowed write. Exit code 1. The error:

Error: Sandbox dependencies not available: socat not installed

The allowed file did not appear. The guarded file kept its original contents, and the outside file did not appear either. Those last two observations prove nothing about enforcement, because the positive control had already failed. The attempt stopped there.

This was the standalone engine, not a native Claude Code shell-tool run. The native file, network and exception checks below are still a proposed procedure. I would rather leave that gap visible than turn an unchanged dummy file into a security claim.

Which platforms support Claude Code sandboxing?

Anthropic's list for the built-in sandbox has macOS, Linux and WSL2. macOS runs it on Seatbelt. Linux and WSL2 run it on bubblewrap, and socat does the network relay. Native Windows commands run unsandboxed. The CLI version on Windows tells you which CLI you have. It does not prove that a shell boundary exists. Platform requirements.

On Windows, do this exercise in a WSL2 distribution. Record that environment separately. Four commands first:

claude --version
uname -a
command -v bwrap
command -v socat

The last two checks apply to Linux and WSL2, not macOS's Seatbelt implementation. On WSL2, note the distribution and the WSL version too. If a dependency is missing, fix it first. Then start a new run. The denials from the failed run say nothing about the repaired environment.

A run can also fail for a reason that has nothing to do with the sandbox. On 26 September 2026 browser tests in my WSL failed at random, 2 runs out of 10. One pytest run hung for over 40 minutes. The cause was /tmp. In my WSL it lives in RAM, 7.7 GB, and it was 100% full. Now df -h /tmp is on my checklist before a long run.

/sandbox shows the active configuration and dependencies. Keep the permission mode too. A screenshot of the panel helps explain the setup. Before I trust the result I still want the command output and an independent file check.

Configure a disposable file and network boundary

No real secret is needed for this test. A dummy text file shows whether a read was blocked just as well. Make a separate directory in your own terminal:

mkdir -p "$HOME/gat-sandbox-fixture/work/guarded"
mkdir -p "$HOME/gat-sandbox-fixture/outside/output"
printf 'dummy only\n' > "$HOME/gat-sandbox-fixture/work/guarded/read.txt"
printf 'unchanged\n' > "$HOME/gat-sandbox-fixture/work/guarded/write.txt"
cd "$HOME/gat-sandbox-fixture/work"

Put this in work as sandbox-test.json. /home/operator is a placeholder, so put your actual home path there. On a Mac it usually starts with /Users/. These paths belong to this fixture. Copy them into a team policy and you protect the wrong files.

{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "autoAllowBashIfSandboxed": false,
    "allowUnsandboxedCommands": false,
    "excludedCommands": [],
    "filesystem": {
      "denyRead": ["/home/operator/gat-sandbox-fixture/work/guarded/read.txt"],
      "denyWrite": ["/home/operator/gat-sandbox-fixture/work/guarded/write.txt"]
    },
    "network": {
      "allowedDomains": ["example.com"],
      "deniedDomains": ["example.org"],
      "strictAllowlist": true
    }
  }
}

Start the session from work:

claude --permission-mode default --settings ./sandbox-test.json

failIfUnavailable makes startup fail if the enabled sandbox cannot start. That is the behavior I want here. allowUnsandboxedCommands: false closes the unsandboxed retry path. strictAllowlist denies hosts outside the list and must come from user, managed or CLI settings, not repository settings. Sandbox settings reference.

The catch is inherited configuration. Settings lists can merge across scopes. An empty excludedCommands array in this file does not erase exclusions elsewhere. Use /status to identify the loaded sources and read those files. Otherwise you can spend an hour testing a policy that is not the policy the process received. Settings precedence and list merging.

I got caught by a scope rule with permission modes, not the sandbox. On 24 September 2026, on Claude Code 2.1.281, a settings file inside the project said bypassPermissions. A fresh session started in manual mode anyway. The value in the project file was ignored. It only worked from my user settings file.

Passing sandbox keys through --settings can also make /sandbox refuse to open because higher-priority settings control them. Change this fixture file and restart. The panel is not a way around that precedence. Higher-priority configuration.

There is another easy way to read the result too generously: sandbox.filesystem.disabled: true leaves network isolation running while removing filesystem isolation. A host denial in that configuration tells you nothing about protected files. Filesystem layer setting.

How do I test network and file restrictions?

Run the allowed write first through Claude's shell tool. Then the denied operations. Keep the exit code, output and permission prompt, and inspect the files from another terminal. Network access gets the same treatment, one allowed host beside one denied host. If both fail, the boundary test did not succeed. You have a problem to investigate.

Do not enter the probes at Claude Code's ! prompt. What you type there usually runs outside the built-in sandbox. Confirm sandboxed commands.

ProbeCommand for Claude to runWhat to verify independently
Allowed writeprintf 'allowed\n' > allowed.txtFile exists in work with that content
Denied writeprintf 'changed\n' > guarded/write.txtOriginal content remains unchanged
Denied readcat guarded/read.txtDummy contents were not returned
Outside writetouch ../outside/output/probe.txtFile was not created
Allowed hostcurl --fail --max-time 15 -I https://example.comRequest reaches the host
Denied hostcurl --fail --max-time 15 -I https://example.orgRequest is refused by the boundary

These are the outcomes the procedure should check. The earlier attempt did not reach this matrix. Stop if either allowed control fails. Keep the exact network error too. An HTTP error is not a DNS failure, and neither of them is a policy refusal. Write "blocked" beside all three and you lose the detail that explains what happened.

I have this in my own notes. On 18 September 2026 a git clone inside a Codex sandbox failed with Failed to connect to github.com port 443. My agent's note said: no network. Two days later we measured it. Outside the sandbox the machine had network. curl to the GitHub API returned 200. The sandbox with its default settings was doing the blocking. The Codex flags around that sandbox are in Codex dangerously skip permissions.

File reads deserve their own row. By default the open source runtime permits broad reads. Writes are allow-only and take deny exceptions. So a path you cannot write to is not automatically a path you cannot read. Test the actual protected paths with dummy files. Runtime filesystem model.

Keep the command, working directory, CLI version, settings hash and observed result together. Add what the independent file inspection found. Next month that record saves you from trying to remember which settings were active. You just rerun the same question. Remove personal paths before sharing it.

Add one exception and check what remains denied

sandbox.filesystem.allowWrite gets one new entry, the absolute path of outside/output. The guarded files stay as they are. Restart with the revised settings file, confirm the loaded settings sources, and ask Claude to repeat the outside write. Then repeat both guarded-file probes.

This is where the boundary gets useful: the output file should appear, but the guarded write and read should still fail. If the exception also opens an unrelated path, go back to the merged settings. Hold on to the original file. With it you can restore the old state and check the original denial again.

The network comparison works the same way, with example.net added to allowedDomains. Test it under the original strict configuration first, then after the change. Leave example.org in deniedDomains and repeat that probe. Then look at both. Did the requested host open, and is the rest of the rule still in place?

Do not touch the command or the timeout between the two runs. Adding a command exclusion to get a request through changes which boundary runs it, so it destroys this comparison. Change the host rule and repeat the request. Then check the host that should still be denied.

Is sandboxing the same as permission approval?

No. Permission rules decide whether Claude may call a tool. The sandbox constrains a running shell process. Read, Edit, Write, WebFetch and MCP tools have their own permission rules. A shell read denied for one path does not establish that every other tool is blocked from it. Permission rules.

The names can make this confusing. Regular permissions mode keeps the permission flow for sandboxed commands. Sandbox auto-allow can approve a contained command. Claude Code's separate auto permission mode uses a classifier. Content-scoped ask rules and deny rules still matter, whichever label you selected. Permission mode pairings.

The separate --dangerously-skip-permissions article covers the bypass flag and its remaining checks. This exercise does not need that flag.

Can a command run outside the sandbox?

Yes. A matching excludedCommands entry runs outside it, and a permitted retry can use dangerouslyDisableSandbox. Turning off unsandboxed retries does not remove inherited exclusions. File tools, hooks and local MCP servers also sit outside the built-in shell boundary. Review that scope before you call the whole agent isolated. Sandbox scope.

The built-in shell sandbox and a container around the whole Claude Code process cover different surfaces. An outer environment is the option to inspect when all tools and helper processes need one boundary. Isolation options.

I would carry the result into the AI agent deployment checks after the allowed probes work, the denied probes fail for the right reason, and the single exception leaves the other restrictions in place. The first attempt here did not get that far. Its useful result was finding the missing dependency before claiming the rest worked.

How does Claude Code sandbox differ from Codex sandbox?

Both keep execution boundaries separate from approval decisions. The platform details differ. On native Windows, Claude's built-in shell sandbox is unavailable. Codex documents a native Windows implementation. Isolation goes through --sandbox, approvals through --ask-for-approval. One documented pairing is workspace-write with on-request. Those are Codex flags, not Claude flags. This comparison comes from the documentation, not a cross-agent experiment. Official OpenAI documentation.

Frequently asked questions

Is sandboxing the same as permission approval?

No. Approval gates a tool call; sandboxing constrains the running shell process. Keep both the permission mode and resolved sandbox settings in your test record.

Which platforms support Claude Code sandboxing?

Anthropic lists macOS, Linux and WSL2. Native Windows is outside that list. Name the WSL2 distribution in a test report instead of calling it native Windows enforcement.

How do I test network and file restrictions?

Use disposable files and harmless hosts. Run allowed and denied probes through Claude's shell tool, inspect file outcomes independently, then add one exception and repeat the original denials. If the allowed probe fails, stop there.

Can a command run outside the sandbox?

Yes. Exclusions and allowed unsandboxed retries can do that. User-entered shell-mode commands usually do too. Inspect inherited settings and the command's execution path before interpreting its result.