Here is the whole problem in one sentence: an AI agent that can write code is worthless until it can run that code, and running code the model wrote is arbitrary code execution wearing a friendly hat.

If you read one line: the moment your agent executes code you didn't write yourself, put that execution inside a disposable sandbox — a throwaway isolated Linux box that boots in under a second and is billed only while it's alive. This is the five-minute, copy-paste path to doing that in E2B and in Modal, with the exact current API — no guessed method names.

Why "just run it" is the wrong instinct#

When your process shells out to python generated_script.py, that script inherits everything your process can do. It can read OPENAI_API_KEY and every other secret from the environment. It can walk your filesystem. It can open a network connection and send whatever it found somewhere else. A try/except around the call does nothing about this — it catches the error after the damage, and the danger was never the crash. It was the capability.

Modal says the quiet part plainly: a Sandbox is "the Modal primitive for safely running untrusted code, whether that code comes from LLMs, users, or other third-party sources," and it exists to limit the blast radius to the sandbox itself. That framing — blast radius — is the right mental model. You are not trying to make the code safe. You are trying to make its failure cheap.

And no, a bare Docker container is not enough on its own; it shares the host kernel. That's the argument we made in full in Your Container Is Not a Sandbox, and it's why the tools below use Firecracker microVMs (E2B) or gVisor syscall filtering (Modal) under the container.

Option A — E2B, the purpose-built agent sandbox#

E2B spins up isolated Firecracker microVMs and hands your agent a real Linux box. New accounts get $100 in credits, sandboxes bill per second, and the default timeout is 300 seconds (adjustable). The one thing to know before you type: there are two E2B SDKs, and they're for different jobs.

1. The base SDK — shell commands

Use e2b when you just need to run commands and read output.

pip install e2b        # or:  npm i e2b
from e2b import Sandbox

# NOTE: it's Sandbox.create(), not Sandbox()
with Sandbox.create() as sandbox:
    result = sandbox.commands.run('echo "Hello from E2B!"')
    print(result.stdout)

The with block guarantees the sandbox is torn down — and billing stops — the instant you're done. That's the pattern you want around anything your agent generates.

2. The code-interpreter SDK — stateful code

Most analysis agents don't want to re-run a whole file; they want a REPL where state carries across calls. That's the other SDK:

pip install e2b-code-interpreter        # or:  npm i @e2b/code-interpreter
from e2b_code_interpreter import Sandbox

with Sandbox.create() as sandbox:
    sandbox.run_code("x = 1")
    execution = sandbox.run_code("x += 1; x")
    print(execution.text)   # -> 2

x survives from the first call to the second because there's a live Jupyter kernel behind the sandbox. This is the primitive your data-analysis agent actually wants: feed it a step, read execution.text, feed it the next step.

Option B — Modal, secure by default#

If your stack already lives on Modal, its Sandboxes are a natural fit — and their default posture is stricter, which is exactly what you want for untrusted code. Modal builds on gVisor, Google's syscall-filtering runtime, and ships with no inbound network by default.

pip install modal
import modal

app = modal.App.lookup("agent-sandbox", create_if_missing=True)

# block_network=True cuts ALL egress — the right default for code you don't trust
sb = modal.Sandbox.create(app=app, block_network=True)
p = sb.exec("python", "-c", "print('hello from a locked-down box')")
print(p.stdout.read())
sb.terminate()

modal.Sandbox.create() returns a sandbox; sb.exec(...) returns a ContainerProcess whose .stdout you read. Setting block_network=True means the generated code can compute but cannot phone home — a good default the first time you let an agent run something you haven't read.

When to reach for which#

All four options below are real answers; pick by where you already are.

OptionIsolationReach for it when
E2BFirecracker microVMyou want an agent-native sandbox with a stateful code interpreter
ModalgVisor containeryou already run Python on Modal and want secure-by-default
Cloudflare SandboxesContainers, on the edgeyou're already on Workers (GA in 2026, billed per active CPU)
Google Cloud Run sandboxesmicroVM inside your instanceyou're on GCP and want no premium (public preview)

We compared these head-to-head, on cost and cold-start, in Which Agent Sandbox in 2026: Cloud Run vs E2B vs Modal vs Fly vs Cloudflare. This piece is the other half: not which one, but how to actually wire one up today.

The one rule to keep#

Sandboxes are cheap because they're short-lived. Create one per task, wrap it in a with block (or terminate() it explicitly), and let idle ones time out. You pay by the second, the security boundary only holds while the box is disposable, and your agent gets exactly what it needs: a place to run its own code where the worst case is a dead sandbox — not a leaked key.

The reflex to build: agent writes code → code runs in a fresh sandbox → sandbox dies. Everything else is detail.