Trying out bubblewrap used in Claude Code's Sandbox Runtime and exploring its network restriction mechanism
llmlinuxClaude Code has a Sandboxing feature that isolates filesystem and network to run agents safely while giving them strong permissions. On Linux, this is implemented using bubblewrap. bubblewrap isolates each namespace by calling the clone(2) system call with flags such as CLONE_NEWNET and CLONE_NEWPID.
$ sudo apt install bubblewrap
$ bwrap \
--ro-bind /usr /usr \
--ro-bind /lib /lib \
--ro-bind /lib64 /lib64 \
--unshare-net \
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
$ bwrap \
--ro-bind /usr /usr \
--ro-bind /lib /lib \
--ro-bind /lib64 /lib64 \
--proc /proc \
--unshare-pid \
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1000 1 0.0 0.0 3584 1420 ? S+ 07:14 0:00 bwrap --ro-bind /usr /usr --ro-bind /lib /lib --ro-bi
1000 2 0.0 0.0 8284 4096 ? R+ 07:14 0:00 ps aux
Unlike Docker, there’s no need to run and communicate with a daemon, allowing execution processes with minimal overhead.
$ time for i in {1..100}; do
echo "test" > /dev/null
done
real 0m0.022s
user 0m0.019s
sys 0m0.003s
$ time for i in {1..100}; do
bwrap --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /lib64 /lib64 --unshare-all echo "test" > /dev/null
done
real 0m0.374s
user 0m0.125s
sys 0m0.095s
$ time for i in {1..100}; do
docker run --rm alpine echo "test" > /dev/null
done
real 0m1.126s
user 0m0.254s
sys 0m0.158s
Sandbox Runtime (srt) uses bwrap --unshare-net to block external communication, while using the socat command to forward the sandbox’s localhost:{port} to a socket, and setting HTTP(S)_PROXY to localhost:{port}, allowing external access through the host’s proxy server. This server performs filtering based on allowed/denied domains.
$ npm install -g @anthropic-ai/sandbox-runtime
$ sudo apt install ripgrep socat
$ srt --version
1.0.0
$ cat ~/.srt-settings.json
{
"filesystem": {
"denyRead": [],
"allowWrite": ["."],
"denyWrite": []
},
"network": {
"allowedDomains": ["example.com"],
"deniedDomains": []
}
}
$ SRT_DEBUG=1 srt curl "sambaiz.net"
...
[SandboxDebug] HTTP proxy listening on localhost:44889
[SandboxDebug] SOCKS proxy listening on 127.0.0.1:44311
[SandboxDebug] Starting HTTP bridge: socat UNIX-LISTEN:/tmp/claude-http-59898d4a7ef502ee.sock,fork,reuseaddr TCP:localhost:44889,keepalive,keepidle=10,keepintvl=5,keepcnt=3
[SandboxDebug] Starting SOCKS bridge: socat UNIX-LISTEN:/tmp/claude-socks-59898d4a7ef502ee.sock,fork,reuseaddr TCP:localhost:44311,keepalive,keepidle=10,keepintvl=5,keepcnt=3
...
[SandboxDebug] No matching config rule, denying: sambaiz.net:80
[SandboxDebug] HTTP request blocked to sambaiz.net:80
Connection blocked by network allowlist[SandboxDebug] Sent SIGTERM to HTTP bridge process
[SandboxDebug] Sent SIGTERM to SOCKS bridge process
Besides, Claude Code’s /sandbox currently does not support Windows including WSL2.
> /sandbox
⎿ Error: Sandboxing is currently only supported on macOS and Linux
However, it can be run using the srt command. You need to allow the required domains to run Claude Code.
$ cat ~/.srt-settings.json
{
"filesystem": {
"denyRead": [
"~/.ssh",
"~/.aws"
],
"allowWrite": [
".",
"/tmp",
"~/.claude.json",
"~/.claude"
],
"denyWrite": [
".env"
]
},
"network": {
"allowedDomains": [
"api.anthropic.com",
"claude.ai",
"statsig.anthropic.com",
"sentry.io"
],
"deniedDomains": []
},
"ignoreViolations": {
"*": [
"/usr/bin",
"/System"
]
}
}
$ srt "claude --dangerously-skip-permissions --print \"run a command: curl sambaiz.net\""
The curl command attempted to connect to sambaiz.net but the connection was blocked by a network allowlist. This means that network access to this domain is restricted in the current environment.
The response shows that only 39 bytes were received before the connection was blocked, suggesting some initial data was retrieved but the full content couldn't be fetched due to network restrictions.