iTranslated by AI
Testing Claude Code's Sandboxing Feature: Network Isolation
In my previous post, I summarized the results of testing "file system level isolation" within Claude Code's sandboxing functionality.
In this post, I have tested "network level isolation," which I didn't cover in the previous one. Note that my environment at the time of writing is macOS Tahoe 26.0.1 and Claude Code 2.0.31.
Trying Out Claude Code's Sandboxing Functionality
The official documentation for Sandboxing is here:
When sandboxing is enabled, access is only permitted within an approved range at the domain level, and requests to access new domains will ask for the user's permission each time. This helps prevent issues such as downloading problematic modules from unauthorized websites or accessing untrusted sites.
Additionally, it seems possible to apply more detailed rules via a custom proxy instead of Claude Code's standard proxy. Although setup might take some effort, I'd like to try this out as well.
Testing Network Isolation
To test Sandboxing's network isolation feature, I'll try cloning a GitHub repository. The contents of the repository are not important, so I'll use an empty repository containing only a README.md. First, I'll try it before enabling the sandboxing feature. Naturally, it succeeds.
> Please git clone "https://github.com/sn6t/claude_code_sandboxing"
⏺ Cloning GitHub repository.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Cloning into 'claude_code_sandboxing'...
⏺ Repository cloning is complete. It has been extracted to the claude_code_sandboxing directory.
I exit Claude Code once, delete the locally cloned repository, and then run the same command with the sandboxing feature enabled. As in the previous post, the sandboxing feature is set to "Accept-edits mode". This time, since I was accessing github.com outside the sandbox environment, I was asked for permission. If you want it to ask for confirmation again the next time you access this domain, select option 1 ("Yes"). This time, I chose option 2 ("Yes, and don't ask again for github.com") to treat github.com as a trusted domain. The repository was successfully cloned.
> /sandbox
⎿ ✓ Sandbox enabled with auto-allow for bash commands when in accept-edits mode
> Please git clone "https://github.com/sn6t/claude_code_sandboxing"
⏺ Cloning Git repository.
Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Cloning into 'claude_code_sandboxing'...
(8s)
ctrl+b to run in background
· Determining… (esc to interrupt)
⎿ Tip: Run claude --continue or claude --resume to resume a conversation
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Network request outside of sandbox
Host: github.com
Do you want to allow this connection?
1. Yes
❯ 2. Yes, and don't ask again for github.com
3. No, and tell Claude what to do differently (esc)
⏺ Bash(ls -la claude_code_sandboxing)
⎿ total 16
drwxr-xr-x 5 john staff 160 Nov 4 08:17 .
drwxr-xr-x 4 john staff 128 Nov 4 08:17 ..
… +3 lines (ctrl+o to expand)
⏺ Successfully cloned the repository to claude_code_sandboxing/. The repository contains:
- .git/ (Git repository data)
- .gitignore
- README.md
>
To see how the settings are configured at this point, the local project-level configuration file at .claude/settings.local.json contains a list of web access domains under the permissions parameter as allowed targets, as shown below. With this configuration, even if the sandboxing feature is enabled, you won't be asked for confirmation for network access during subsequent GitHub repository clones.
% cat ./.claude/settings.local.json
{
"sandbox": {
"autoAllowBashIfSandboxed": true,
"enabled": true
},
"permissions": {
"allow": [
"WebFetch(domain:github.com)"
]
}
}
Now, let's see what happens if we change this 'allow' to 'deny'. After deleting the locally cloned repository, I changed the settings in settings.local.json from 'allow' to 'deny' and tried the same steps as before. This time, it was denied. I was also asked to disable the sandboxing feature, which I refused. As a result, the repository cloning failed.
% cat ./.claude/settings.local.json
{
"sandbox": {
"autoAllowBashIfSandboxed": true,
"enabled": true
},
"permissions": {
"deny": [
"WebFetch(domain:github.com)"
]
}
}
% claude
6 "Please git clone https://github.com/sn6t/claude_code_sandboxing"
⏺ I'll clone the repository for you.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Error: Exit code 128
Cloning into 'claude_code_sandboxing'...
fatal: unable to access 'https://github.com/sn6t/claude_code_sandboxing/': CONNECT tunnel failed, response 403
⏺ The git clone failed due to sandbox network restrictions. Let me retry with sandbox disabled to allow the network
connection to GitHub.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Interrupted · What should Claude do instead?
When sandboxing is disabled, network communication is permitted even if the above 'deny' setting exists in .claude/settings.local.json. Therefore, the webFetch permission settings only take effect when the sandboxing feature is enabled.
6 /sandbox
⎿ ○ Sandbox disabled
6 "Please git clone https://github.com/sn6t/claude_code_sandboxing"
⏺ Sandbox is now disabled, so I will clone the repository.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Cloning into 'claude_code_sandboxing'...
⏺ Repository cloning is complete. Let me check the contents.
⏺ Bash(ls -la claude_code_sandboxing)
⎿ total 16
drwxr-xr-x 5 john staff 160 Nov 4 08:41 .
drwxr-xr-x 4 john staff 128 Nov 4 08:41 ..
… +3 lines (ctrl+o to expand)
⏺ Successfully cloned the repository. The claude_code_sandboxing directory has been created.
Repository contents:
- .gitignore
- README.md
Would you like to check the contents of README.md?
6
The .claude/settings.local.json file we've been using is a local project-level configuration file. What happens if we deny it in the shared project-level configuration file (.claude/settings.json) when the local one doesn't exist? I tried the following, and it seems that the 'deny' setting in ./claude/settings.json is effective in this case. Instead of a domain-level access permission check, I was asked to authorize disabling the sandboxing feature.
% cat settings.local.json
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true
}
}
% cat ./.claude/settings.json
{
"sandbox": {
"autoAllowBashIfSandboxed": true,
"enabled": true
},
"permissions": {
"deny": [
"WebFetch(domain:github.com)"
]
}
}
% claude
6 "Please git clone https://github.com/sn6t/claude_code_sandboxing"
⏺ I'll clone the repository for you.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Error: Exit code 128
Cloning into 'claude_code_sandboxing'...
fatal: unable to access 'https://github.com/sn6t/claude_code_sandboxing/': CONNECT tunnel failed, response 403
⏺ The sandbox is blocking network access to GitHub. Let me retry with sandbox disabled to access the repository. Use
/sandbox to manage restrictions.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Interrupted · What should Claude do instead?
6
Testing a Custom Proxy
Next, I will test the custom proxy. I set up Squid on my local machine (macOS Tahoe 26.0.1) and check the connection. I install Squid via Homebrew, start the service, and verify that communication is possible and that Squid's access logs are being generated. I open another shell window to perform the tasks there, while running tail -f on the access log in the original shell (this step isn't strictly necessary, as it just displays the access log in real-time as it's updated).
% brew install squid
% brew info squid
==> squid: stable 7.3 (bottled), HEAD
% brew services start squid
==> Successfully started `squid` (label: homebrew.mxcl.squid)
% curl https://www.google.com -x http://localhost:3128
<!doctype html>(omitted)</html>
% cat /opt/homebrew/var/logs/access.log
1762226934.497 547 ::1 TCP_TUNNEL/200 24089 CONNECT www.google.com:443 - HIER_DIRECT/142.250.196.100 -
% tail -f /opt/homebrew/var/logs/access.log
1762226934.497 547 ::1 TCP_TUNNEL/200 24089 CONNECT www.google.com:443 - HIER_DIRECT/142.250.196.100 -
In the settings.local.json configuration, I specify the Squid proxy I just set up as the HTTP proxy server and launch Claude Code. In this state, the sandboxing feature is not enabled. Since it's not enabled, the repository cloning succeeds without any issues, and no access logs are generated for the Squid proxy. This means the custom proxy server is not being used.
% cat settings.local.json
{
"sandbox": {
"network": {
"httpProxyPort": 3128
}
}
}
% claude
> Please git clone "https://github.com/sn6t/claude_code_sandboxing"
⏺ I'll clone the repository for you.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Cloning into 'claude_code_sandboxing'...
⏺ The repository has been successfully cloned! Let me check what's in it:
⏺ Bash(ls -la claude_code_sandboxing)
⎿ total 16
drwxr-xr-x 5 john staff 160 Nov 4 12:46 .
drwxr-xr-x 4 john staff 128 Nov 4 12:46 ..
… +3 lines (ctrl+o to expand)
⏺ The repository has been cloned to /path/to/your/sandbox/claude_code_sandboxing. Let me show you the
README:
⏺ Read(claude_code_sandboxing/README.md)
⎿ Read 1 line
⏺ Successfully cloned the repository! It's now located at /path/to/your/sandbox/claude_code_sandboxing.
The repository currently contains:
- .gitignore
- README.md (with just the title "claude_code_sandboxing")
The repository appears to be minimal at the moment. Is there something specific you'd like to do with it?
After deleting the local repository, I launched Claude Code again, enabled the Sandboxing feature, and performed the same action. This time, even though Sandboxing was enabled and I hadn't specified either allow or deny in the webFetch settings of settings.local.json, the repository clone was successful.
> /sandbox
⎿ ✓ Sandbox enabled with auto-allow for bash commands when in accept-edits mode
> Please Git Clone "https://github.com/sn6t/claude_code_sandboxing"
⏺ Cloning the Git repository.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Cloning into 'claude_code_sandboxing'...
⏺ Repository clone is complete. The claude_code_sandboxing directory has been created.
Additionally, an access log for github.com was output in the Squid logs. This suggests that when the Sandboxing feature is enabled and a custom proxy server is being used via the httpProxyPort setting, the webFetch permission settings seem to have no effect.
% tail -2 /opt/homebrew/var/logs/access.log
1762226934.497 547 ::1 TCP_TUNNEL/200 24089 CONNECT www.google.com:443 - HIER_DIRECT/142.250.196.100 -
1762228272.180 1058 ::1 TCP_TUNNEL/200 7428 CONNECT github.com:443 - HIER_DIRECT/20.27.177.113 -
To verify, I'll check what happens if I explicitly set a 'deny' configuration in settings.local.json. I deleted the repository cloned to my local machine and retried the same process, but it succeeded. Therefore, it confirms that when Sandboxing is enabled and a custom proxy is configured via httpProxyPort, the webFetch permission settings in settings.local.json are indeed ignored.
% cat settings.local.json
{
"sandbox": {
"network": {
"httpProxyPort": 3128
},
"enabled": true,
"autoAllowBashIfSandboxed": true
},
"permissions": {
"deny": [
"WebFetch(domain:github.com)"
]
}
}
% claude
> Please Git Clone "https://github.com/sn6t/claude_code_sandboxing"
⏺ I'll clone the repository for you.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Cloning into 'claude_code_sandboxing'...
⏺ The repository has been successfully cloned into the claude_code_sandboxing directory. Let me check what's inside:
⏺ Bash(ls -la claude_code_sandboxing)
⎿ total 16
drwxr-xr-x 5 john staff 160 Nov 4 13:41 .
drwxr-xr-x 4 john staff 128 Nov 4 13:41 ..
… +3 lines (ctrl+o to expand)
⏺ The repository has been successfully cloned into /path/to/your/sandbox/claude_code_sandboxing. The
repository contains:
- .gitignore
- README.md
The clone is complete and ready to use.
Finally, I will set access restrictions on the Squid proxy server side to check the behavior. In the Squid configuration file squid.conf, I will set access restrictions for .google.com and .github.com using acl blocked_sites. Then, I confirmed that web access to google.com is blocked.
% brew services stop squid
Stopping `squid`... (might take a while)
==> Successfully stopped `squid` (label: homebrew.mxcl.squid)
% vi /opt/homebrew/etc/squid.conf
% cat /opt/homebrew/etc/squid.conf
(omitted)
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl blocked_sites .google.com .github.com
#
# Recommended minimum Access Permission configuration:
#
# Deny requests to certain unsafe ports
http_access deny !Safe_ports
(omitted)
% brew services start squid
==> Successfully started `squid` (label: homebrew.mxcl.squid)
% curl https://www.google.com -x http://localhost:3128
curl: (7) Failed to connect to localhost port 3128 after 0 ms: Couldn't connect to server
I'll try the same process as before with Claude Code where the Sandboxing feature is enabled. This time, the repository clone failed because it was denied by the Squid custom proxy server. Also, I was prompted to disable the Sandboxing feature, which I refused.
% claude
> Please Git Clone "https://github.com/sn6t/claude_code_sandboxing"
⏺ I'll clone that repository for you.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Error: Exit code 128
Cloning into 'claude_code_sandboxing'...
fatal: unable to access 'https://github.com/sn6t/claude_code_sandboxing/': Failed to connect to localhost port 3128
after 0 ms: Couldn't connect to server
⏺ The command failed due to sandbox network restrictions blocking access to github.com. Let me retry with sandbox
disabled.
⏺ Bash(git clone https://github.com/sn6t/claude_code_sandboxing)
⎿ Interrupted · What should Claude do instead?
As cleanup, I'll delete settings.local.json and uninstall Squid, which was installed via Homebrew.
% rm /path/to/your/sandbox/.claude/settings.local.json
% brew services stop squid
Stopping `squid`... (might take a while)
==> Successfully stopped `squid` (label: homebrew.mxcl.squid)
% brew uninstall squid
Uninstalling /opt/homebrew/Cellar/squid/7.3... (162 files, 7.9MB)
Warning: The following may be squid configuration files and have not been removed!
If desired, remove them manually with `rm -rf`:
/opt/homebrew/etc/squid.conf.default
/opt/homebrew/etc/squid.conf.documented
%
In this post, I configured and verified the operation of the network isolation feature among Claude Code's Sandboxing capabilities. Being able to confirm communication to websites you don't want accessed at the domain level before execution provides a better sense of security than having nothing at all. On the other hand, personally, I'm not a fan of being asked to disable the Sandboxing feature through the same interface when access is denied.
Along with the file-system-level (actually directory-path-level) isolation feature, I personally feel it might be better if it acted more like a guardrail that blocks access without requiring too much thought. However, I hope that it will become an even more user-friendly feature based on various feedback.
Discussion