alternatives - pprados/pysandboxes GitHub Wiki
Snapshot of 2026-10-01. Every open-source project was cloned and read at the commit given in Sources; closed services were assessed from their technical documentation, security pages and independent reviews. Projects move fast: re-check a claim before relying on it.
PySandboxes is not alone in trying to run code written by a model without handing it the machine. This page compares it with eighteen other solutions. Some are open-source frameworks you embed, some are open-source platforms you operate, and some are cloud services you rent. The comparison concentrates on what each solution actually enforces, how it enforces it, and where its approach differs from ours.
- Method
- The landscape
- Five different bets
- The network, protocol by protocol
- Feature matrix
- Solution by solution
- Primary source examples
- Where PySandboxes stands
- Sources and commits analysed
Open projects were assessed from source; closed services from vendor documentation and independent reviews. Findings were then checked against a common grid of 45 features in twelve families. This helps surface missing features as well as advertised ones.
Evidence is identified as:
- code: read in the source, cited by a link pinned on a commit plus the function or type name;
- doc: stated by the vendor's documentation;
- third party: an independent review, a disclosure or a CVE.
Absence claims refer to the inspected commit. CVEs were checked against NVD, OSV, or the GitHub Advisory Database; items confirmed only by secondary sources are labelled.
| Solution | Kind | Boundary that holds against hostile native code | Licence |
|---|---|---|---|
| PySandboxes | Python framework | Python API patching, inside one OS provider: Landlock, bubblewrap, Firejail, unshare, QEMU | Apache-2.0 |
| RestrictedPython | Python library | None. AST rewriting at compile time, guards supplied by the host | ZPL-2.1 |
| smolagents | Agent framework | None for the local AST interpreter. The remote executors delegate to Docker, E2B, Modal or Blaxel | Apache-2.0 |
| langchain-sandbox | Python library, archived | Pyodide (CPython compiled to WASM) under Deno permissions | MIT |
| NVIDIA OpenShell | Agent runtime, self-hosted | Landlock, seccomp-notify broker, seccomp kill-list, then a container or a microVM | Apache-2.0 |
| Anthropic sandbox-runtime | CLI and library (Claude Code) | bubblewrap and seccomp on Linux, Seatbelt on macOS, plus a host-side proxy | Apache-2.0 |
| OpenAI Codex sandbox | Sandbox built into the Codex CLI | Seatbelt on macOS, bubblewrap and seccomp on Linux, restricted token and WFP on Windows, or MXC | Apache-2.0 |
| microsandbox | Local microVM runtime | libkrun microVM (KVM, Hypervisor.framework, WHP) | Apache-2.0 |
| E2B | Platform, SaaS or self-hosted | Firecracker microVM | Apache-2.0 (open core) |
| Daytona | Platform | Docker container under Sysbox, --privileged by default |
AGPL-3.0, frozen at v0.190.0 |
| OpenSandbox | Platform, Docker or Kubernetes | runc by default; gVisor, Kata or Firecracker as options | Apache-2.0 |
| Kubernetes agent-sandbox | Kubernetes controller | Whatever the RuntimeClass provides: runc, gVisor or Kata |
Apache-2.0 |
| llm-sandbox | Python library | The Docker, Podman or Kubernetes container, unhardened by default | MIT |
| Modal Sandboxes | Cloud service, open client | gVisor, or a VM on request | Closed platform |
| Vercel Sandbox | Cloud service, open client | Firecracker microVM | Closed platform |
| Cloudflare Sandbox | Cloud service, open client | Container inside a Firecracker microVM | Closed platform |
| AWS Bedrock AgentCore Code Interpreter | Cloud service | Documented as "containerized"; reported as a Firecracker microVM by third parties | Closed |
| Azure Container Apps dynamic sessions | Cloud service | Hyper-V, one VM per session | Closed |
| Docker Sandboxes | Local product for coding agents | A microVM with its own kernel and Docker Engine | Closed |
The isolation primitives these solutions build on are covered in our own provider pages (Choosing a provider) and, for the ones we do not ship, in their upstream documentation: gVisor, Firecracker, Kata Containers, libkrun, Cloud Hypervisor and Pyodide.
Other services (Blaxel, Northflank, Google's Gemini and Vertex code execution, Beam) appear in most comparisons. They were looked at briefly and are not in the grid. Blaxel runs Firecracker with an SNI-based egress proxy, and its vendor admits that Encrypted Client Hello defeats SNI filtering. Northflank lets the workload choose between Kata, gVisor and Firecracker, and documents no fine network policy. Google's two code-execution products have no network access at all and do not name their isolation technology.
Almost every solution adopts one of five strategies. The differences between solutions come from that choice far more than from any single feature.
1. Guard the language. PySandboxes, RestrictedPython and smolagents' local executor control Python operations, with different mechanisms. PySandboxes also requires an OS boundary; its Python layer alone does not hold against compiled code (Weaknesses).
2. Confine a process and proxy its traffic. OpenShell, sandbox-runtime and Codex combine OS restrictions with an external proxy. Depending on the product, policies can inspect hostnames, HTTP fields, credentials, or caller identity. This adds network visibility but requires proxy integration.
3. Put a machine around the code. MicroVMs and gVisor provide a stronger boundary against hostile native code, with lifecycle features such as snapshots and persistent volumes. Network defaults vary by product; the guest may still run with broad privileges.
4. Orchestrate containers. agent-sandbox, OpenSandbox, llm-sandbox and Daytona rely on a container runtime selected by the operator. Their guarantees depend on that runtime and on configured policy.
5. Run Python as WebAssembly. langchain-sandbox combines Pyodide and Deno permissions; the project is archived.
PySandboxes combines language-aware rules with a selectable kernel boundary. It can confine one function and learn its policy; it does not provide a whole-machine boundary or an L7 proxy.
OpenShell is a good starting point, because it gets one thing exactly right: it decides what to block by
the protocol in use, not by the destination alone. Its seccomp-notify broker sorts every socket at creation.
A UDP socket can only reach the sandbox's own DNS relay or loopback; connect() and sendto() anywhere else
return EACCES. An ICMP socket is never created (EPROTONOSUPPORT). On top of that, it adds L7 rules for
REST, GraphQL, JSON-RPC, MCP and WebSocket, behind a TLS interception, and rules on the binary making the
call. So the opening example holds once read in the code: OpenShell does not handle UDP, but it filters at
layer 7, and it grants privileges on more than the network destination alone.
| Solution | Default egress | UDP | ICMP | DNS | Domain rules | Layer 7 | Credentials |
|---|---|---|---|---|---|---|---|
| PySandboxes | Deny at the Python layer. At the OS layer: unshare and qemu set iptables to DROP; bwrap and firejail leave only loopback when the profile has no net= rule; with net= rules under an explicit restricted-network yes, firejail keeps the host network and warns |
net= rules, enforced by Python and iptables. landlock cannot filter UDP |
No rule can name it; blocked as a side effect | Names resolved once and pinned into getaddrinfo
|
Name resolved to IPs when the profile is parsed | None |
env= whitelist; a granted secret enters the sandbox in clear |
| OpenShell | Deny | Only to the DNS relay | Socket never created | Own relay, policy per name | Proxy CONNECT + OPA |
REST, GraphQL, JSON-RPC, MCP, WebSocket, TLS interception | Placeholders, SigV4, SPIFFE to OAuth2 |
| sandbox-runtime | Open if allowedDomains is undefined; the CLI closes it |
Impossible: the netns has only loopback | Impossible | Resolved by the proxy after the allow decision | HTTP and SOCKS proxy | Optional TLS interception; domain fronting acknowledged | Masked credentials, SigV4 re-signed |
| Codex | Deny on Linux and macOS; on Windows (restricted token), allow with a WFP deny-list | Blocked by seccomp (Linux Restricted mode) | Blocked on Windows by WFP | Resolved by the proxy, rebinding checked | Optional proxy | Method, path, headers (optional proxy) | Credential broker scoped per host |
| microsandbox | Public internet allowed, private ranges and metadata denied | Relay with session tracking | Echo only, gated by policy | Interception, rebinding defence, pinning | SNI checked against the DNS pin | TLS interception per host, no method or path rules | Placeholders, gated by pin and SNI |
| E2B (open source) | Allow; allow_out alone restricts nothing |
CIDR only (nftables) | Same as UDP |
8.8.8.8 forced open, even when locked down |
SNI and Host header, userspace proxy |
None in the open-source runtime (cloud only) | Cloud only |
| Daytona | Allow on tiers 3 and 4 | IPv4 CIDR, all protocols together | Same | Not mediated |
domainAllowList accepted but never enforced |
None | None |
| OpenSandbox | Open without networkPolicy; deny with one |
Timing of DNS leases | IPv6 neighbour discovery only | Own proxy, NXDOMAIN on denial |
FQDN and wildcards | mitmproxy and addons | Credential vault in the sidecar |
| k8s agent-sandbox | Allow except private ranges and metadata (template) | Like TCP | Left to the CNI | Redirected to public resolvers | None | None | None |
| llm-sandbox | Open (Docker bridge) | Not mediated | Not mediated | Not mediated | None | None | None |
| langchain-sandbox | Deny | No socket layer in Pyodide (not tested) | Same | Not mediated | Deno --allow-net host list |
None | None |
| Modal | Open | CIDR list "any protocol" (doc) | Not found | Blocked with block_network
|
SNI, port 443 only | None | Header injection per domain |
| Vercel | allow-all |
Not documented | Not documented | Open under subnets.allow (documented) |
SNI; domain fronting acknowledged | Matchers on method, path, query and headers; transform, forward or respond; Postgres aware | Header transform, secret never inside |
| Cloudflare | Open (enableInternet true); closed, only 80 and 443 leave, through the interception |
None | None | Not documented | JavaScript written in the Worker | Anything the Worker code does | In the Worker, on fictitious host names |
| AWS AgentCore | Three modes (sandbox, public, VPC) | DNS leaked in sandbox mode | Not documented | The exfiltration channel | None | None | IAM role |
| Azure dynamic sessions | Deny (EgressDisabled) |
Not documented | Not documented | Not documented | None | None | Managed identity, off by default |
| Docker Sandboxes | Deny, with presets | Experimental, gated by policy | Blocked | Mediated by the proxy | Allow and deny per host | Host name only | Injected by the proxy |
Three observations follow.
- UDP and ICMP are where most solutions are vague. Only OpenShell, sandbox-runtime, Codex on Linux and microsandbox give a precise, code-backed answer. Most platforms let any protocol through to an allowed CIDR. Others simply do not document it.
-
DNS is the most common leak. It made AgentCore's "sandbox" mode a command channel
(BeyondTrust,
Unit 42, HackerOne report
3323153). It stays open on
Vercel when only CIDRs are allowed, and on E2B, by construction, as soon as a domain rule exists.
PySandboxes pins names to the addresses resolved when the profile is parsed, which closes the TTL drift.
When a provider uses
iptables, the sandbox still talks to a resolver (DNS and iptables). - Layer 7 belongs to the proxy-based solutions. Rules on HTTP method and path exist only behind a proxy: OpenShell, Codex, Vercel, Cloudflare (as code), OpenSandbox (through addons) and sandbox-runtime (partly). Credential injection, where the real secret never enters the sandbox, is common: nine of the nineteen solutions do it fully, three more partly. PySandboxes does neither.
Y yes, P partial, N no, - not applicable, ? no source says either way (closed services).
The default egress posture (N1) does not fit a yes/no cell; it is in the
table above. The policy format (C1) is left out: every solution has
one, as a file, API arguments or code, so the row says nothing.
Columns: pysb PySandboxes, RPy RestrictedPython, smol smolagents, lcsb langchain-sandbox, OShl OpenShell, srt sandbox-runtime, Cdx Codex, msb microsandbox, E2B E2B, Dayt Daytona, OSbx OpenSandbox, k8s Kubernetes agent-sandbox, llms llm-sandbox, Modl Modal, Verc Vercel, CF Cloudflare, AWS AgentCore, Azur Azure dynamic sessions, DkSb Docker Sandboxes.
| ID | Feature | pysb | RPy | smol | lcsb | OShl | srt | Cdx | msb | E2B | Dayt | OSbx | k8s | llms | Modl | Verc | CF | AWS | Azur | DkSb |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| I1 | Boundary that holds against hostile native code | P | N | P | Y | Y | Y | P | Y | Y | Y | P | P | P | Y | Y | Y | P | Y | Y |
| I2 | Host-side confinement of the runtime or VMM itself | P | - | ? | N | P | Y | Y | N | P | P | Y | N | - | ? | Y | ? | ? | ? | ? |
| I3 | Choice of isolation backends | Y | Y | Y | N | Y | N | P | N | N | P | Y | Y | Y | Y | N | N | N | N | N |
| N2 | IP/CIDR and port rules | Y | N | N | P | Y | Y | P | Y | P | Y | Y | Y | N | Y | Y | P | P | N | P |
| N3 | UDP handling | P | N | N | ? | Y | Y | P | Y | P | P | P | P | P | P | ? | N | P | ? | P |
| N4 | ICMP handling | N | N | N | ? | N | N | P | P | N | N | P | N | P | N | ? | N | ? | ? | N |
| N5 | DNS mediation | P | N | N | N | Y | Y | P | P | P | N | Y | P | N | P | P | ? | N | ? | Y |
| N6 | SSRF: private ranges, metadata, rebinding | P | N | N | N | Y | Y | Y | Y | Y | N | P | P | N | ? | N | N | ? | ? | Y |
| N7 | Domain/FQDN rules | Y | N | N | P | Y | Y | P | Y | Y | P | Y | N | N | Y | Y | Y | N | N | Y |
| L1 | TLS interception | N | N | N | N | Y | Y | P | Y | N | N | Y | N | N | P | Y | Y | N | N | Y |
| L2 | HTTP method / path / header / query rules | N | N | N | N | P | P | Y | N | N | N | P | N | N | N | Y | Y | N | N | N |
| L3 | Protocol-aware rules beyond HTTP | N | N | P | N | P | N | N | N | N | N | P | P | N | N | P | N | N | N | N |
| L4 | Credential injection / brokering | N | N | P | N | Y | Y | Y | Y | P | N | Y | N | N | Y | Y | Y | N | P | Y |
| L5 | Identity of the caller in network policy | N | N | N | N | Y | P | P | N | N | N | P | P | N | N | N | N | N | N | N |
| F1 | Path-level read/write allow/deny | Y | N | N | Y | Y | Y | Y | Y | N | N | Y | P | P | N | N | N | ? | N | P |
| F2 | Copy-on-write / overlay / ephemeral rootfs | P | - | P | P | Y | N | P | Y | Y | Y | Y | N | P | N | ? | ? | Y | ? | ? |
| F3 | Safe file transfer host and sandbox | P | - | N | - | P | P | P | Y | ? | Y | Y | Y | Y | ? | ? | P | P | ? | P |
| S1 | Syscall filtering | P | N | N | P | Y | P | Y | N | P | N | N | N | P | Y | Y | - | ? | ? | ? |
| S2 | Control of process execution | Y | N | P | Y | P | P | Y | P | P | Y | Y | Y | N | P | N | N | ? | ? | ? |
| S3 | Code runs unprivileged by default (not root, not privileged) | P | - | N | - | P | Y | P | N | P | N | P | N | N | ? | N | ? | ? | ? | ? |
| P1 | Import control | Y | N | Y | N | - | N | N | N | - | - | N | N | N | N | N | N | - | - | - |
| P2 | Sensitive call control beyond imports | Y | N | P | N | - | N | N | N | - | - | N | N | N | N | N | N | - | - | - |
| P3 | Control of eval / exec / compile
|
Y | P | Y | N | - | N | N | N | - | - | N | N | N | N | N | N | - | - | - |
| P4 | AST restriction / rewriting | Y | Y | Y | N | - | N | N | N | - | - | N | N | N | N | N | N | - | - | - |
| P5 | Per-function granularity | Y | P | P | P | - | - | - | - | - | - | - | - | P | - | - | - | - | - | - |
| C2 | Default deny for everything | Y | P | P | P | Y | P | P | P | N | N | P | N | N | N | N | N | P | P | P |
| C3 | Live update without restart | N | - | N | N | Y | P | P | N | Y | Y | Y | Y | N | Y | Y | Y | ? | Y | Y |
| C4 | Learning / advisor mode | Y | N | N | N | Y | N | P | N | N | N | N | N | N | N | N | N | N | N | N |
| C5 | Formal verification of the policy | N | N | N | N | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
| C6 | Human approval loop for denied actions | P | N | N | N | Y | Y | Y | P | N | N | N | N | N | N | N | N | N | N | N |
| K1 | Environment filtering / secret scrubbing | Y | N | N | Y | Y | Y | Y | P | N | P | Y | N | N | P | N | P | N | N | Y |
| E1 | Cold start / warm pool | P | - | P | N | N | - | P | P | P | Y | Y | Y | Y | Y | Y | ? | ? | Y | ? |
| E2 | Snapshot, pause/resume, fork | N | - | N | P | P | N | N | Y | Y | Y | Y | N | N | Y | Y | P | N | N | N |
| E3 | Persistence across sessions | N | - | P | Y | Y | P | P | Y | Y | Y | P | Y | P | Y | Y | Y | N | N | N |
| R1 | CPU / memory limits | P | N | P | P | P | N | N | Y | Y | Y | Y | Y | P | Y | Y | P | ? | P | P |
| R2 | Timeouts / operation budgets | Y | P | Y | Y | Y | N | Y | Y | Y | Y | P | P | Y | Y | Y | P | Y | Y | N |
| R3 | GPU | N | - | N | N | Y | N | N | N | N | Y | P | Y | N | Y | N | N | ? | P | ? |
| O1 | Decision log, structured denial for the agent | P | P | P | N | Y | Y | P | P | P | Y | Y | P | N | N | N | N | Y | P | P |
| D1 | Linux / macOS / Windows | P | Y | Y | P | Y | P | Y | Y | P | P | P | N | P | - | - | - | - | - | Y |
| D2 | Self-host / SaaS / Kubernetes | P | - | P | P | P | P | P | P | Y | Y | Y | Y | P | Y | Y | Y | Y | Y | Y |
| D3 | Enforcing code is open | Y | Y | Y | Y | Y | Y | Y | Y | P | P | Y | Y | Y | P | P | P | N | N | N |
| G1 | SDKs, MCP, agent frameworks | Y | P | Y | P | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
| G2 | Safety of results returned to the host | Y | - | Y | Y | P | - | ? | P | Y | Y | Y | Y | Y | P | ? | P | ? | ? | ? |
Two rows stand out. The language-level rows (P1 to P5) are empty for every solution outside family 1. Learning or advisor mode (C4) exists only in PySandboxes and OpenShell, and partly in Codex, which adds one allow rule per human approval.
-
Bet: a single declarative
.py-sandboxeswhitelist, recorded by running the real application once in learning mode, then enforced twice. Python guards apply it inside the interpreter, and an OS provider translates it into a kernel boundary. -
Strengths: the only solution that controls imports, a registry of 149 sensitive functions in eight
categories (
guard_api), and code arriving as a string (theeval-*sub-language: parsed, rewritten, run under a budget and a timeout). It is the only one granular to the function (@sandbox). Its results are unpickled under a guard (Transport unpickle guard). Five interchangeable kernel providers are available. -
Weaknesses: no layer 7, no TLS interception, no credential brokering. A granted secret enters the
sandbox in clear. There is no built-in list of private ranges or metadata addresses: the profile author has
to write the
DENYrules. No rule can name ICMP.landlockcannot filter UDP. A change of profile needs a restart. Kernel boundaries exist on Linux and WSL only. The Python layer's known escapes are listed in Weaknesses and the two security assessments.
-
Bet: rewrite the AST once at compile time, deny any node type without a
visit_method, and route attribute and item access through hooks the host supplies. - Strengths: small (about 2,300 lines), a long history, and a very frank security page: "The guards are a second line of defence, not the boundary" (security_considerations.rst).
-
Weaknesses: no resource limit, no timeout, no policy on modules, files or network. All of that is left
to the host. The whitelist only catches new node types: the Python 3.15 audit had to add explicit checks
for lazy imports and comprehension unpacking. Six advisories, all sandbox escapes or leaks, listed on
the project's advisories page:
CVE-2023-37271, CVE-2023-41039, CVE-2024-47532,
CVE-2025-22153, CVE-2026-55830 and CVE-2026-76825 (
string.Formatter, fixed in 8.4).
- Bet: an AST interpreter written in Python for convenience, and outside services for real isolation.
-
Strengths: actual operation and loop budgets (
MAX_OPERATIONS,MAX_WHILE_ITERATIONS). A 30 s timeout, and a check of every node's return value (@safer_evalonevaluate_ast). -
Weaknesses: it is the default executor. The timeout cannot kill its thread, as its own docstring says.
DANGEROUS_MODULESis never read by the enforcing code; a test only uses it as a list of names. TheDockerExecutorsets no network, capability or memory limit. CVE-2025-5120 and CVE-2025-9959 were sandbox escapes. Issue 2094 (ctypes) is still open.
- Bet: let Deno permissions and WASM do all the work.
-
Strengths: every permission is closed in the constructor's signature (network, environment, run, FFI).
Session state round-trips through
dillas opaque bytes, without the host ever unpickling it. -
Weaknesses: archived, and its own README advises against production use. With
allow_read=False, read and write access to the host'snode_modulesis still granted. The Python wrapper pins a published JSR package older than the source in the repository. Code and session travel asargv, which fails withE2BIGon large payloads.
- Bet: move the whole trust boundary out of the agent's process and language.
-
Strengths: per-protocol socket control in a privileged seccomp-notify broker. Policy keyed on the
binary's identity: path, SHA-256 trusted on first use, ancestor chain, and script paths taken from the
command line, because "the interpreter (node) is the exe"
(
NetworkInput). L7 rules for REST, GraphQL, JSON-RPC, MCP and WebSocket, written in Rego. Two checks backed by an SMT solver (Z3): a whole-policy exfiltration prover (openshell-prover), and a containment check for advisor proposals against an approved baseline (containment.rs). A policy advisor: the agent can propose a narrow rule after a denial, and a human approves it. Live policy update. -
Weaknesses: no ICMP, and UDP only to the DNS relay, by design. No view of what the interpreter does.
Outside the Docker driver (
network_mode=none), no network namespace without a route was found: the broker alone stands between the workload and raw egress. The containment check does not model GraphQL, JSON-RPC or MCP extensions. NVD lists three critical or high CVEs against versions up to 0.0.33: CVE-2026-65093 (escape, CWE-427), CVE-2026-65083 (provisioning API) and CVE-2026-65091 (command injection from a malicious gateway). CVE-2026-65086 is reported by the press, not confirmed in a registry.
- Bet: wrap an unmodified process tree in bubblewrap and a narrow seccomp filter (Seatbelt on macOS), and route every byte through a host-side proxy that filters by host name.
-
Strengths: no UDP or ICMP at all, because the network namespace has only loopback. SSRF pinning on the
resolved address, independent of the name list. Masked credentials with
AWS SigV4 re-signing,
so a secret can sign an allowed request without ever entering the sandbox. A seccomp filter that blocks
Unix-domain sockets
(
seccomp-unix-block.c). -
Weaknesses: reads are open by default. Network is unrestricted when
allowedDomainsis undefined. The vendor acknowledges domain fronting (Claude Code sandboxing). One policy per command, no learning mode. One low-severity advisory, CVE-2025-66479, fixed in 0.0.16.
-
Bet: the operating system as the only enforcement point. Four native backends are chosen per platform,
and a decision layer (
execpolicyprefix rules, human approval) sits above them. -
Strengths: a three-mode seccomp filter that also closes an
io_uringtoAF_VSOCKbypass (landlock.rs). A loopback-only bridge into the network namespace, carrying a per-exec attribution token. An optional proxy with method, path and header rules, and a credential broker scoped per host. Allow rules accrue one human approval at a time. -
Weaknesses: on Windows, the restricted-token backend allows by default with a short deny-list (ICMP,
DNS, SMB). The proxy is optional. Published incidents hit the decision layer above the sandbox, not the
kernel boundary: CVE-2025-59532 (fixed in 0.39.0),
CVE-2026-19591 (Codex CLI 0.72 to 0.130) and CVE-2026-19593 (
.git/configread by Codex Desktop).
-
Bet: one hardware-virtualised microVM, with libkrun on all three operating systems, and a user-space
network stack (
smoltcp) on the host. - Strengths: the richest L3/L4 handling of all: a UDP relay with sessions, ICMP limited to echo, DNS interception with rebinding defence and DNS-to-IP pinning, SNI checked against the pin, secrets injected only when all three agree. The refusal page is written for an LLM to read ("Ask the user to add it...").
-
Weaknesses: no host-side confinement of the VMM process (no seccomp, Landlock or namespace found in the
runtime crates), so a hypervisor escape inherits the user's rights. Root inside the guest by default. No
L7 method or path rules.
CVE-2026-61670 (secrets visible in
/proc/<pid>/cmdline) was fixed in 0.5.10.
- Bet: a Firecracker microVM per sandbox, restored from a snapshot, plus host-side network mediation.
-
Strengths: an SSRF check placed exactly between DNS resolution and
connect()(see Primary source examples). Pause with a copy-on-write memory export, so the VM resumes before its dirty pages are written. Self-hostable on AWS, GCP, Kubernetes or Compose. -
Weaknesses: egress is allowed by default, and
allow_outwithoutdeny_out: ["0.0.0.0/0"]restricts nothing. As soon as a domain rule exists,8.8.8.8is open on every protocol and port, and cannot be closed. Nojailer. TLS interception, header injection and bring-your-own-proxy exist only in the closed cloud build: the open-source orchestrator rejects them withUnimplemented. The legacy v1 API leavesenvdunauthenticated unlesssecureis set.
- Bet: Sysbox-hardened Docker containers, with developer ergonomics: fast boot, volumes, snapshots, forks.
- Strengths: a full machine-like environment. Live network update on paid tiers. A protocol-blind IPv4 CIDR filter.
-
Weaknesses: containers run
--privilegedoutside GPU and Android sandboxes. No IPv6, DNS or ICMP handling, no L7.domainAllowListis validated and forwarded by the API but never read by the runner. The repository'smainsays the code "moved to a private codebase": the open source is frozen at v0.190.0. A batch of advisories in June 2026, all fixed by 0.185.0: CVE-2026-54320 (invitation accepted without a verified e-mail), CVE-2026-54321 (stale preview-visibility cache), CVE-2026-54324 (WebSocket notifications leaked across organisations) and CVE-2026-54323 (git clonewithout TLS verification). A path traversal, CVE-2026-54319, was rated not exploitable in any released version.
- Bet: own the network layer. An egress sidecar does DNS enforcement plus nftables, with FQDN rules and mitmproxy.
-
Strengths: fail closed (
NXDOMAINfor denied names; the sidecar refuses to start open). A credential vault that refuses to activate outsidedns+nftmode. L7 extensible with mitmproxy Python addons, the closest thing in the field to writing a guard by hand. Memory and disk pause/resume on microVMs. -
Weaknesses: no sidecar, so no filtering, unless the request carries a
networkPolicy. The default DNS-only mode can be bypassed by direct IP. gVisor, the strongest syscall isolation it offers, is incompatible with the sidecar.
-
Bet: a thin Kubernetes layer (
Sandbox,SandboxTemplate,SandboxClaim,SandboxWarmPool). Every security property is delegated to theRuntimeClass, the CNI and admission control. - Strengths: standard objects, warm pools, and a documented fix for a cross-tenant attack through Service-selector label spoofing.
-
Weaknesses: its own threat model says "Agent Sandbox itself does not implement isolation". The
template's default egress allows everything except private and metadata ranges, and DNS goes to public
resolvers. A bare
Sandboxgets none of that. The router's default authoriser isAllowAll.
- Bet: orchestration convenience over containers you already run.
-
Strengths: fail-closed tar extraction (
tarfile.data_filter), written after GHSA-crfw-xvcm-hjxj (found on the repository, not yet in the global database). Package-name allow-lists per ecosystem, against shell injection. -
Weaknesses: root, open network and no limits by default.
runtime_configsis passed through unfiltered, as its own documentation warns.SecurityPolicyis a regex thatrun()never calls.
- Bet: gVisor, or a VM, plus a small set of network settings validated by the client.
-
Strengths: block, CIDR list or domain list, mutually exclusive and checked before the call. Header
injection with
$KEYtemplates, where the secret never enters the sandbox. GPU, and GPU memory snapshots driven by gVisor's checkpoint. - Weaknesses: network open by default. The domain list only covers TLS on port 443, matched by SNI. gVisor is a user-space kernel: CVE-2026-96812 (escape through CUSE passthrough) and CVE-2025-2713 affect gVisor itself. Whether they apply to Modal's deployment is not known.
- Bet: a Firecracker microVM and the richest declarative network policy in the field.
- Strengths: CIDR and domain rules, matchers on method, path, query and headers, and exactly one action per rule: transform, forward or respond. TLS interception only on the hosts that need it, with a CA per sandbox. Policy replaced while the sandbox runs. Very candid documentation of its own pitfalls (Firewall).
-
Weaknesses:
allow-allby default. DNS open undersubnets.allow. Domain fronting acknowledged. UDP and ICMP not documented.
- Bet: no policy language at all. The policy is JavaScript in the Worker, and the container sits in a Firecracker microVM.
-
Strengths: as expressive as code can be: rules with state, changed without a redeploy. Credentials
reached through fictitious host names (
*.sandbox.internal) that exist only inside the interception. - Weaknesses: nothing validates the policy, and every application rewrites its own. With internet on, nothing filters. A cross-tenant leak of residual disk data (dm-thin pools without block zeroing) was fixed in September 2026 (Cloudflare's disclosure).
- AWS AgentCore Code Interpreter: three network modes and an IAM role, nothing finer. In "sandbox" mode, DNS leaked and was turned into a command channel. AWS first called it intended behaviour. The SDK had an argument injection, CVE-2026-16796.
- Azure dynamic sessions: one Hyper-V VM per session, at the scale of Copilot. Egress is a single on/off switch per pool, closed by default. The managed identity is off by default; the documentation warns that turning it on lets any code in the session mint tokens.
-
Docker Sandboxes: a microVM with its own Docker Engine. Deny by default with presets, rules per host,
credentials injected by the proxy. In 2026, its file-sharing bridge was the weak point:
CVE-2026-77179 and
CVE-2026-79994 (symlink TOCTOU escapes), and
CVE-2026-17106, a bug in the shared
moby/go-archivelibrary.
These source locations support the key distinctions in the comparison:
- OpenShell network broker: protocol-specific socket decisions.
- E2B TCP firewall: internal-address rejection before connect.
- Vercel network policy types: mutually exclusive rule actions.
- Cloudflare example policy: deny, handler, allow, then default deny.
- RestrictedPython AST transformer: unknown AST nodes are refused.
What only PySandboxes does. No other solution in this survey controls what the Python code itself does. That means imports, a registry of 149 sensitive functions, and code arriving as a string, which is parsed, rewritten and run under a budget. It is the only solution that confines one function rather than a process, a pod or a VM. It is one of two that write their own policy from observed behaviour; OpenShell is the other, with an advisor rather than a recording. Unlike most solutions, which avoid the problem by never unpickling, it returns real Python objects from the sandbox, and it unpickles them under a guard. And it lets the user choose among five kernel boundaries, from Landlock with no extra binary up to a full QEMU VM.
What the field does better.
- A stronger default boundary. Platforms give every sandbox its own kernel. PySandboxes' strongest option, QEMU, is a full VM, not a microVM restored from a snapshot, and the four other kernel providers share the host kernel.
-
The network above layer 4. There is no TLS interception, no method or path rules, no protocol-aware
rules. Nine solutions match domain rules on the live connection (SNI,
Host, proxy). PySandboxes resolves names once, when the profile is parsed. - Secrets. The pattern "the secret never enters the sandbox" (placeholders, header injection, SigV4 re-signing) is widespread. PySandboxes filters the environment, but a granted secret is passed in clear.
- SSRF by default. Most proxy-based solutions deny private ranges and the cloud metadata address without being asked. PySandboxes leaves it to the profile author.
- Live operations. Live policy update, human approval of a denied action, a denial structured so the agent can understand it, snapshots and warm pools: most of the field has some of these, PySandboxes has none.
Limits this comparison brings to the fore.
- No rule can name ICMP. ICMP is only blocked as a side effect, and the
IPPROTO_ICMPentry of theiptablesgenerator (netfilter.py) is never used. -
landlockcannot filter UDP, which the Landlock page already says.
Ideas worth borrowing, in decreasing order of value for the effort.
- A built-in deny list for private ranges, link-local and metadata addresses, as E2B, microsandbox and sandbox-runtime have.
- Credential placeholders for the network: the sandbox sees a token, and the proxy or the parent swaps it for the real value on allowed hosts only.
- A host-name-aware HTTP proxy for the providers that already run
slirp4netnsor a VM, which the Roadmap already lists. - OpenShell's idea of tying a network rule to the caller, which PySandboxes could apply at a finer grain
than anyone else: to the
@sandboxfunction, not to the binary. - A structured denial addressed to the agent, as OpenShell and microsandbox do, so a model can ask for the right rule instead of guessing.
| Solution | Analysed at |
|---|---|
| PySandboxes |
pprados/pysandboxes, develop at bda508f
|
| RestrictedPython | c5066f7 |
| smolagents | c30b115 |
| langchain-sandbox | fac037c |
| OpenShell |
021400b, docs
|
| sandbox-runtime |
5d196e0, Claude Code sandboxing
|
| Codex | 444da31 |
| microsandbox |
b3843eb (v0.7.5) |
| E2B | SDK f713914, runtime 23f7a0f, docs
|
| Daytona | v0.190.0 01c502b
|
| OpenSandbox | c7dc78a |
| Kubernetes agent-sandbox | 82d410e |
| llm-sandbox | 7361f5e |
| Modal | client 83cd277, networking, security
|
| Vercel | client 6fc8e16, firewall
|
| Cloudflare | client f9e972a (1.0 preview), Containers outbound traffic
|
| AWS AgentCore | AgentCore documentation, BeyondTrust, Unit 42 |
| Azure dynamic sessions | Container Apps sessions |
| Docker Sandboxes | Docker Sandboxes documentation |
CVE numbers were checked on 2026-10-01. Only CVE-2026-65086 (OpenShell) was seen in secondary sources alone, and it is quoted as such.