The first time I let an agent run its own code on a server I cared about, it deleted a directory it should not have been able to see. Nothing important. A tmp folder with a half-written script. But the agent had no business knowing the path existed, and the only reason it did was that I had given it a shell on a box that also had a copy of my dotfiles mounted in. The shell was supposed to be scoped. It was not. It was just a child process with a different working directory and a hopeful name.
That was the moment sandboxing stopped being a feature I would get to later and started being the prerequisite for any agent that produces code I plan to execute. Two years on, the tooling for this is finally good. There are at least four production-grade options for running untrusted code on demand, plus the underlying primitives if you want to roll your own. They are not interchangeable. The differences between them are the difference between an agent that works for one customer and an agent that scales to a thousand without melting your bill or your blast radius.
This is what I have learned about picking one and using it without regret.
Why You Cannot Just Run It Locally
The pitch for skipping sandboxing is that you trust your agent. You wrote the prompts. You picked the model. The code it generates looks reasonable when you read it. What is the worst that could happen.
The worst that could happen has a long list. The agent gets prompt-injected by a tool result and writes a script that exfiltrates env vars. The agent installs a package that turns out to be a typosquat. The agent runs an infinite loop that pegs the box. The agent writes a recursive shell that fork-bombs the machine. The agent exfiltrates the contents of /etc/passwd because someone asked it nicely in a comment. None of these are theoretical. They have all happened to people I know who shipped agent products in the last eighteen months. The reason they survived is that the code ran somewhere it could not hurt anything important.
The principle is simple. If a model produces the code, the code is untrusted. Untrusted code does not run on a host that has access to your secrets, your database, your filesystem, or your network. It runs in a fresh environment with the smallest possible set of capabilities and the shortest possible lifetime. When it is done, you throw the environment away.
This is the same containment posture you would apply to user-uploaded code in a build pipeline. It is not new. What is new is that AI agents are now the largest source of untrusted code in most apps that ship one, and most teams have not adjusted their security model accordingly. The same caution I wrote about for AI-generated code security risks applies double when you also let the model push the run button.
What A Real Sandbox Looks Like
The word “sandbox” gets used loosely. A Docker container with default settings is not a sandbox for adversarial code. A chroot is not a sandbox. A Linux user without sudo is not a sandbox. These all reduce blast radius for accidental mistakes. They do not stop a determined script.
The bar for code you do not control is higher. The sandbox needs hardware-level isolation, ideally a microVM or a strongly confined container. The filesystem is ephemeral. The network is either off entirely or restricted to a specific allowlist. There is no path back to the host that did not get explicitly opened. The lifetime is measured in minutes or hours, not days. When it dies, nothing it produced survives unless you fished it out through a controlled channel.
The four products in this comparison meet that bar. The shape of the isolation differs. The ergonomics differ a lot more.
E2B
E2B was the first product that made sandboxed code execution feel like an SDK call instead of an infrastructure project. You install a client, you call Sandbox.create(), you run code, you read the result. The sandbox is a Firecracker microVM with a writable filesystem and a configurable lifetime. It comes pre-installed with Python, Node, and a pile of common tooling, so the agent does not have to install half the world before it can do its job.
The thing E2B got right was the developer experience. The SDK feels like calling a remote shell. You can stream stdout. You can mount files. You can keep a sandbox alive across multiple agent turns so the agent can iterate on the same workspace, then tear it down at the end. Persistent sandboxes for sessions that need to remember installed deps and intermediate state are a real productivity win because the agent does not have to redo setup work on every turn.
Where E2B costs you is concurrency at scale. The base tier is generous, but if you are running thousands of concurrent sandboxes for a real product, you start to feel the pricing. You can negotiate, but the unit economics matter and you should run the numbers before committing.
The other thing to watch is the trust model. E2B is a third party. Code your agent runs on E2B is running on E2B’s infrastructure. They are reputable and the architecture is solid, but if you have customers whose contracts say their data does not leave systems you control, E2B is a hard sell without a self-hosted variant. They have one for enterprise. It is not the cheapest path.
E2B is the right call when you are early, you want to ship now, and you are not yet in a contractual position where you need to own the runtime. It is also the right call for prototyping any sandboxed-execution feature, because nothing else gets you to a working agent faster.
Vercel Sandbox
Vercel Sandbox went GA in January 2026 and changes the math for any team already on Vercel. It is also a Firecracker-based microVM, but it is plumbed into the same project, deployment, and billing surface as your functions. You spawn a sandbox from a Function or Routing Middleware, you get back a handle, you run code, you read the result. The lifetime caps at a few hours and the billing aligns with your existing compute budget rather than landing on a separate invoice.
The integration is the killer feature. You do not have to set up a second account, a second set of credentials, a second observability stack. The same logs, the same dashboard, the same env vars you are already using are wired in. For a team building an agent product on Vercel, this is the path of least resistance and the one with the lowest ongoing maintenance cost.
The ceiling shows up if you outgrow the Vercel platform’s resource limits per sandbox. Long-running ML training is not what these are for. Heavy GPU work is not what these are for. They are sized for code execution that completes in minutes, not hours of model inference. If your agent’s job is “run this Python script and tell me what happened,” they are exactly right. If your agent’s job is “fine-tune a model on this data,” look elsewhere.
The other consideration is that Vercel Sandbox is the youngest of the four. The API is good and the abstractions are clean, but the long tail of edge cases the older products have already absorbed is still being filled in. For most workloads this is invisible. For a few weird ones it is the difference between a clean integration and a workaround.
If your stack is already on Vercel, this is the default, and you should have a hard reason to pick something else. The combination of Fluid Compute reusing function instances and Sandbox handling untrusted execution is a clean separation of concerns that most agent products end up reinventing badly when they roll their own.
Modal
Modal is the option to reach for when the workload is heavier than what code-execution sandboxes are designed for. It started as a serverless Python runtime for ML and adjacent workloads and has since grown into a full code-execution platform with strong sandbox primitives. You define a function in Python with decorators that describe the environment, the resources, and the lifetime. Modal handles provisioning, scaling, and teardown. The mental model is closer to “serverless runtime for arbitrary code” than “remote shell for an agent.”
Where Modal pulls ahead is anything that needs serious compute. GPUs are first-class. Long-running jobs are first-class. Storage volumes that persist across runs are first-class. If your agent is producing code that does real work, like training a small model, processing a large dataset, or running a simulation, Modal will handle it natively and the rest of the products on this list will struggle.
The tradeoff is that Modal is more opinionated. The decorator-based function model is great when your code fits the shape, less great when you want a generic shell that the agent can drive freely. You can do that on Modal. It is not what the platform optimizes for. The agents that thrive on Modal are the ones whose tools are well-defined functions with typed inputs and typed outputs, not open-ended REPLs.
The other thing to know is that Modal’s pricing is real. Active CPU and GPU time at production scale is not cheap. It is competitive with the alternatives once you account for what you are actually running, but you cannot pretend the bill is going to be small. Build a cost model before you scale up, not after.
Modal is the right pick when the agent’s outputs are computational, not just exploratory. If the LLM is writing code that has to actually run a job that matters, Modal is where it should run.
Daytona
Daytona is the dev-environment-as-a-service approach. Instead of a one-shot sandbox, you get a full development workspace with an editor surface, a filesystem, a terminal, and a network policy you can configure. It is the product you reach for when the agent is collaborating with a human, or when the workload looks more like “explore a repository and make changes” than “run a single script.”
The fit for AI agents is interesting. A Daytona workspace can be the agent’s home for a session, with the agent writing code, running tests, iterating on failures, and producing a diff at the end. The lifetime is longer than a code-execution sandbox. The environment is richer. The network and filesystem policies are configurable per workspace, so you can lock down what the agent can reach without giving up the productivity of a real development environment.
Daytona is also a good answer when the agent’s job involves an existing codebase. Cloning a repo, running its tests, making a fix, and producing a PR is a workflow that fits a workspace better than a function call. The agent gets to behave like a developer rather than like a script runner. For products in the AI code review and automated-PR space, this is the natural shape.
The cost shape is closer to “developer seats” than “function invocations,” which is right for some products and wrong for others. If you are running thousands of short tasks a day, this is not the model. If you are running tens of long-form sessions a day where each one is a real piece of work, the math lines up.
Daytona is the call when the agent’s surface is “act like a developer in a workspace” rather than “execute this code and tell me what happened.”
Building Your Own
The four products above are the ones I would actually pick from in 2026. The reason to roll your own is narrower than it used to be, but it still exists.
If you have hard data-residency or compliance requirements that the managed options cannot meet, you may have to. Firecracker is open source. So is gVisor. So is the underlying tech. You can run microVMs on your own hardware or your own cloud account. The cost is a serious infra team and the long tail of edge cases that the managed products have already solved.
If your workload is so specific that none of the products fit, you may have to. This is rare and getting rarer. The four options above cover most agent workloads cleanly.
If you have a paranoid security model that requires every byte of execution to be on infrastructure you fully control, you may have to. This is a real reason and the right one. Self-hosted Firecracker on your own VPC with your own monitoring and your own kill switches is a reasonable answer for some companies.
For everyone else, building your own sandbox in 2026 is the same mistake as building your own auth in 2018. The right answer is to pick the managed product whose tradeoffs match your workload and spend your time on the agent itself.
What To Lock Down Regardless
Whichever product you pick, there is a set of controls that should not be optional. Most of these are off by default in the SDKs because they get in the way of the demo. Turn them on before you ship.
Network egress should be blocked by default and opened only to the specific hosts the agent needs. The most common exfiltration path for agent-generated code is “agent decides to curl somewhere with a payload built from env vars.” If the network cannot reach arbitrary hosts, that path closes. Allowlist the package registry and the APIs the agent legitimately needs. Block everything else.
Filesystem mounts should be read-only or scoped writable. The agent should not have write access to anything you would not be willing to throw away. Mount input data read-only. Give the agent a writable scratch directory. When the sandbox dies, the scratch dies with it.
Secrets should not live in the sandbox’s environment. If the agent needs to call an authenticated API, broker the call through your own service that injects the credentials at the network boundary. The sandbox should never see the raw secret. Even with strong isolation, a leaked secret in a logged stdout line is a real failure mode.
Resource limits should be set explicitly. CPU. Memory. Wall-clock time. Disk. Without these, a runaway script will keep running until it hits a platform limit or eats your budget. Most of the SDKs default to permissive limits because tight limits break legitimate workloads. Tune them down to what your workload actually needs.
Logging should capture every command and every output. Not for compliance theater, but because you will need to debug agents that did weird things, and the only way to debug a non-deterministic process is to have a complete record of what happened. The same observability discipline I talked about for debugging AI agents in production applies here. The sandbox is part of the agent. Treat it as such.
Lifetimes should be aggressive. The longer a sandbox lives, the more chance it has to be exploited or to leak state across users. Default to short lifetimes, with explicit extension when the workload needs it. Persistent sandboxes are convenient. They are also a small attack surface that compounds with every session.
Patterns That Hold Up
A few patterns have survived contact with production for me, and they are worth lifting out as defaults.
One sandbox per user, never one sandbox shared across users. Even if the work is “stateless,” cross-user sandboxes are how data leaks happen. Pay the cold-start cost.
Inject the model’s plan, not the model’s code, when you can. If the agent’s job is “run a query against a database,” let the agent produce a structured query that your code executes against a connection it owns, not Python code that opens a connection itself. The sandbox is for things you cannot pre-shape. Pre-shape what you can.
Capture artifacts explicitly. If the agent produces a file you want to keep, the agent’s tool should be “save artifact named X with these bytes,” and your code should write it to the storage you control. Reading files out of an exiting sandbox after the fact is fine for debugging and bad for production. Make the artifact transfer explicit.
Run a non-network “thinking” sandbox first when the agent’s plan is long. Let it draft. Let it reason. Then move to a network-enabled sandbox only for the steps that need the network, with a tighter scope. This staged approach reduces the blast radius without crippling the agent’s ability to plan.
Validate every tool result the agent acts on. The output of a tool call is a vector for prompt injection. The agent should treat tool results as data, not as instructions. The framework cannot enforce this for you. It is a discipline.
Picking One
The decision tree is short.
If you are on Vercel and your workload is code execution, pick Vercel Sandbox.
If you are not on Vercel, your workload is code execution, and you want the smoothest SDK experience, pick E2B.
If your workload is computational and needs real CPU, GPU, or long jobs, pick Modal.
If your workload is “act like a developer in a real workspace,” pick Daytona.
If your contract says the runtime has to live on infrastructure you control, build on Firecracker yourself and accept the operational cost.
The wrong answer is to keep running untrusted code in containers you control on hosts that touch your data. That worked when “untrusted code” meant a CI build of your own repo. It does not work when “untrusted code” means whatever the model produced this turn, on a turn-by-turn basis, for every user you have. The volume of untrusted code in agent products is the new variable, and the security architecture has to match.
Where This Goes
The trend that matters is the convergence of agent frameworks and sandboxing primitives. A year ago, picking a framework and picking a sandbox were two separate decisions with manual wiring between them. The newer frameworks ship with sandbox adapters out of the box. The newer sandbox products ship with framework integrations that make the boundary nearly invisible.
The next step is sandboxes that share more state cheaply. Right now, every cold start is a real cost. The frameworks are getting better at warm pools and shared base images. Fluid Compute showed what is possible when instances are reused intelligently. Sandboxes will get the same treatment. The cost curve for running thousands of concurrent untrusted environments is going to bend down.
The other thing to watch is the policy layer. Right now, configuring network and filesystem policy is per-product, per-SDK, per-workload. There is room for a higher-level abstraction that lets you express “this agent is allowed to do X but not Y” once and have it enforced across whichever runtime executes the work. That is not here yet. It is being prototyped.
The deletion incident I started with was a year and a half ago. I would not get away with it now. Not because I have gotten more careful, though I have. Because the tooling has caught up to the problem. Sandboxing AI-generated code is a solved problem in 2026 in the same way that running customer-facing apps in containers was a solved problem in 2018. You still have to do it. You no longer have to invent it. That is real progress, and it is the part of agent infrastructure where you can buy a meaningful chunk of safety with a reasonable amount of integration work.
Do that work. The first time an agent in your product tries to do something it should not, you will be glad it tried inside a box you can throw away.