# Anthropic sandbox-runtime (srt), Explained — and How to Harden It (Oct 2026) > What Anthropic's newly open-sourced sandbox-runtime (srt) actually is, how it confines an AI agent's filesystem and network without a VM, the limits it is honest about, and a 13-point hardening checklist. Source: https://playciso.com/blog/anthropic-sandbox-runtime-srt-explained · Published: 2026-10-23 · Publisher: PlayCISO (https://playciso.com) --- Your AI agent can run shell commands, install packages and reach the network on your behalf. So what stops a prompt-injected or compromised agent from reading your SSH keys and POSTing them to an attacker's server? In October 2026 Anthropic open-sourced the tool it built for exactly that question: **sandbox-runtime**, CLI name `srt`. This post explains what it is, how it works, where it is honest about its own limits, and ends with a concrete hardening checklist you can apply today. ## What srt is `srt` is, in its README's own words, **"a lightweight sandboxing tool for enforcing filesystem and network restrictions on arbitrary processes at the OS level, without requiring a container."** Anthropic describes it as "a research preview developed for Claude Code to enable safer AI agents." The Claude Code documentation confirms the relationship verbatim: **"Claude Code builds the sandbox on the open source @anthropic-ai/sandbox-runtime package."** - Package: @anthropic-ai/sandbox-runtime on npm; CLI: srt. - Install: npm install -g @anthropic-ai/sandbox-runtime. Linux also needs bubblewrap and socat; ripgrep is used for deny-path detection. - License: Apache-2.0. - Status: Beta Research Preview ("APIs and configuration formats may evolve"); Windows is alpha. It is not limited to Claude Code. The README states it "can be used to sandbox the behaviour of agents, local MCP servers, bash commands and arbitrary processes." Usage is simply `srt ` — for example `srt npm install` or `srt --debug curl https://example.com` — and there is a library API (`SandboxManager.initialize()` then `wrapWithSandbox()`). Crucially, restrictions "cover any scripts, programs, or subprocesses that are spawned by the command," so child processes inherit the sandbox. Primary sources, all worth reading: the [sandbox-runtime GitHub repository](https://github.com/anthropics/sandbox-runtime), the [Anthropic engineering blog on Claude Code sandboxing](https://www.anthropic.com/engineering/claude-code-sandboxing), and the [Claude Code sandboxing docs](https://code.claude.com/docs/en/sandboxing). ## How it works `srt` leans on native OS primitives rather than a virtual machine. The README: it "uses native OS sandboxing primitives (`sandbox-exec` on macOS, `bubblewrap` on Linux) and proxy-based network filtering." PlatformMechanism **macOS**`sandbox-exec` with dynamically generated Seatbelt profiles; the profile allows communication only to a specific localhost proxy port. **Linux**`bubblewrap` with network-namespace isolation. The sandboxed process's network namespace is removed entirely, so all traffic must go through host-side proxies reached over Unix sockets bind-mounted into the sandbox. Unix-socket blocking uses seccomp filters (x86-64/arm64 only). **Windows**_Alpha._ A dedicated `srt-sandbox` local user account, a Windows Filtering Platform egress fence keyed on that account's SID, a write-restricted token, and ACLs on the work tree. Gappier than macOS/Linux — see Limitations. ### Network: deny-by-default, enforced off-box The README is blunt: **"By default, all network access is denied. You must explicitly allow domains."** Enforcement does not live inside the sandbox — it lives in two proxies running on the host: an **HTTP proxy** for HTTP/HTTPS and a **SOCKS5 proxy** for other TCP. A connection is evaluated in order: a `deniedDomains` match denies; else an `allowedDomains` match allows; else, under `strictAllowlist`, it is denied; else a per-command list is consulted; else an "ask" callback decides (no callback means denied). In Claude Code, that "ask" is the permission prompt. There is also a resolved-address safety net: allowed hostnames are resolved and any address in a denied set — loopback, link-local, multicast, **cloud-metadata endpoints** (169.254.169.254), and the host's own interface addresses — is dropped. That is a built-in SSRF and metadata-exfiltration guard. ### Filesystem: writes closed, reads open This is the single most important thing to internalize. With no settings file, the default posture is **"no network access, no writes outside the default write paths, and unrestricted reads."** The precedence rules: - Reads are deny-then-allow — open by default. "By default, read access is allowed everywhere." allowRead takes precedence over denyRead. - Writes are allow-only — closed by default. denyWrite takes precedence over allowWrite. - Network is allow-only — closed by default. Policy lives in a JSON settings file (`~/.srt-settings.json` by default, or `--settings `) with `network` and `filesystem` sub-objects: `{ "network": { "allowedDomains": ["github.com", "*.github.com", "npmjs.org", "*.npmjs.org"], "deniedDomains": ["malicious.com"], "allowUnixSockets": ["/var/run/docker.sock"], "allowLocalBinding": false }, "filesystem": { "denyRead": ["~/.ssh"], "allowRead": [], "allowWrite": [".", "src/", "test/", "/tmp"], "denyWrite": [".env", "config/production.json"] } }` One genuinely good behaviour to call out: a settings file that exists but fails validation is a **hard error**. `srt` exits rather than silently falling back to defaults — fail-closed, which is what you want. ## The security-versus-usability balance Anthropic frames sandboxing as a way to cut "approval fatigue" — the safety erosion that happens when a human clicks "approve" on every prompt without reading it. The engineering blog reports that sandboxing **"safely reduces permission prompts by 84%"** in internal usage. Treat that as _Anthropic's reported internal figure_, from the engineering blog; we have not independently verified it, and it was not found in the portion of the public docs we reviewed. The tension runs both ways. Too strict, and real workflows break — the README documents several: Jest/Watchman permission errors (`srt "jest --no-watchman"`); Chromium/Electron, rootless podman and nested bubblewrap failing with `EPERM` unless `allowNestedUserNamespaces: true` (which the README warns weakens guarantees); Go tools needing `enableWeakerNetworkIsolation` to verify TLS against the MITM proxy; and Ubuntu 24.04+ needing an AppArmor adjustment. Too loose, and the sandbox stops meaning anything — the opt-out switches each trade away a guarantee (more below). Anthropic's core design statement captures why both dimensions are mandatory: **"Without file isolation, a compromised process could exfiltrate SSH keys or other sensitive files. Without network isolation, a process could escape the sandbox and gain unrestricted network access."** ## The honest limitations To Anthropic's credit, the README documents what `srt` does _not_ protect against. Keep these front of mind — they are where over-trust bites. - Not a VM, not a complete isolation boundary. The docs say so outright. A kernel-level exploit is out of scope. - Reads are open by default. You must hand-write deny lists for secrets. Forgetting this is the most likely real-world misconfiguration. - Content-blind domain filtering. The proxy "does not otherwise inspect the traffic" — "allowing github.com lets a process push to any repository," and in some cases filtering "may be ... bypass[ed] through domain fronting." - Unix sockets are host-takeover holes. Allowing /var/run/docker.sock "would effectively grant access to the host system." On Linux without seccomp, Unix sockets are unrestricted (warning only). - Writable-$PATH is a code-execution escalation. Allowing writes to $PATH dirs, system config or shell rc files "can lead to code execution in different security contexts." And a writable /node_modules/ copy of srt "can be rewritten by a sandboxed command, and the next srt there runs the result unsandboxed." - The weakening switches remove guarantees. enableWeakerNetworkIsolation is a "potential data exfiltration vector through the trustd service"; allowAppleEvents means "the sandbox no longer provides code-execution isolation"; allowNestedUserNamespaces means the mandatory denies "no longer hold"; enableWeakerNestedSandbox "considerably weakens security." - Linux proxy bypass. Routing relies on HTTP_PROXY/HTTPS_PROXY/ALL_PROXY, which "may be ignored by programs that don't respect these variables." (The mandatory network-namespace enforcement is the stronger lever here.) - Attribution, not a boundary, between concurrent commands. A sandboxed process presenting another live invocation's id gets that invocation's allows — "this is attribution, not a boundary between concurrent commands of one session." - No structured Linux audit. macOS can tap the sandbox violation log (log stream --predicate 'process == "sandbox-exec"'); on Linux bubblewrap has no built-in violation reporting and you bolt on strace (strace -f srt 2>&1 | grep EPERM). On denial, `srt` does three things: it **blocks the operation** at the OS level (returns `EPERM`), **logs the violation** via platform-specific mechanisms, and **notifies the user** (a permission prompt in Claude Code). ## Hardening checklist — 13 concrete controls Each item maps to a real `srt` mechanism. This is the "how to keep it secure" list. - Deny-by-default everywhere you can. Writes and network are already closed — keep them minimal. Never widen to allowWrite: ["/"] or a blanket domain. - Fix the read-default gap first. Reads are OPEN by default. Explicitly denyRead secret stores: ~/.ssh, ~/.aws, ~/.config, .env, .npmrc, cloud creds, SSH/GPG keys, browser profiles. This is the single most important manual step. - Least-privilege filesystem. allowWrite only the project tree plus a scratch dir (/tmp). Never allow writes to $PATH dirs, system config, or shell rc files — that is a code-execution escalation path. Keep srt installed globally, not in a project-writable node_modules/. - Network allowlist discipline. Allowlist exact domains (registry.npmjs.org, github.com, your API host), not broad wildcards. Remember the allow is coarse: github.com allows push to any repo. For path/method control, use a custom proxy rule set. - Guard SSRF and metadata endpoints. Rely on (and verify) the resolved-address denylist that drops loopback, link-local, multicast and cloud-metadata (169.254.169.254) targets. Never allow a domain that resolves into internal ranges. - Treat Unix sockets as privilege grants. Never allowUnixSockets for docker.sock (= host takeover) unless you fully accept that. On Linux, confirm seccomp is active (x86-64/arm64) so sockets are actually filtered; a seccomp-unavailable warning means they are NOT. - Don't flip the weakening switches by reflex. enableWeakerNetworkIsolation, allowAppleEvents, enableWeakerNestedSandbox, allowAllUnixSockets and allowNestedUserNamespaces each remove a guarantee. Use only with a documented reason and compensating isolation. - Fail closed, validate config. Lean on srt exiting on an invalid settings file; keep the policy in version control and lint it in CI. No silent default fallback. - Audit the denials. Pipe strace / log-stream violations somewhere durable (SigNoz, syslog) so a wall of EPERMs is visible, not just a transient prompt. Review what the agent tried to reach. - Defence in depth — don't treat it as a VM. For untrusted code or high-value hosts, nest srt inside a container or microVM. OS-primitive confinement does not survive a kernel exploit. - Scope check for Claude Code specifically. The built-in Bash sandbox covers shell commands only; file tools, hooks and local MCP servers run with full access. For one boundary, run the whole Claude Code process under srt (or in a container/VM). - Pin and review the policy per project. Different repos need different allowlists; a single global ~/.srt-settings.json drifts wide. Prefer --settings per project. - Mind Linux proxy bypass. Env-var proxying can be ignored by non-conforming programs. Prefer the mandatory network-namespace enforcement and watch for tools that open raw sockets. ## Bottom line `srt` is a welcome, well-documented default: a low-overhead way to put filesystem and network boundaries around an agent without standing up a container for every command, and the only lightweight local tool of its kind that ships a deny-by-default _domain_ allowlist out of the box. But its own docs are clear that it is confinement, not containment. Treat it as the inner layer — fix the reads-open default, keep allowlists tight, audit denials, and nest it inside stronger isolation when the code is genuinely untrusted. For how `srt` stacks up against bubblewrap, Firejail, Docker, gVisor, Firecracker and the cloud sandbox services, see our [agent sandbox comparison](/blog/agent-sandbox-comparison-srt-vs-alternatives-2026).