Sandboxing LLM Tool Calls vs Full Code Execution
LLMs that write code need stronger sandboxing than those that call tools.

Tool calls are scoped by design. The function signature defines what the LLM can pass and what the function can do, which means the surface available for misuse is bounded before execution begins. That is a structural property of the model, not a security guarantee, but it does constrain the threat surface in ways that matter when you are building something. But what if that structural constraint is less protective than it appears?
The primary risk vectors in tool calling have little to do with arbitrary execution. Prompt injection is the most consequential: adversarial content embedded in a tool's output can manipulate subsequent LLM behavior, turning a benign-looking result into an instruction. Overprivileged tools compound this. A tool that can read files, write to a database, or call external APIs carries ambient authority the LLM never explicitly requested and may not understand it has. Chained tool abuse follows logically; individually innocuous calls can compose, across a sequence, into something harmful.
What the sandbox must prevent here is unauthorized side effects, credential leakage through inputs and outputs, and cross-agent contamination in multi-agent setups. What it does not need to do is contain an arbitrary process tree, intercept syscalls from generated code, or manage a filesystem the LLM wrote into existence.
The isolation strategy for tool calls is therefore about policy and permission scoping: least-privilege interfaces, network egress controls, output sanitization. Not hardware-level process containment. The pattern that works in practice is treating the LLM as a regular service that invokes tools running in isolated environments it can call but cannot escape into. The boundary is the interface, not the kernel.
For teams working within the current ecosystem, the Model Context Protocol (MCP) is the dominant interface through which LLMs discover and invoke tools. MCP defines a structured negotiation between the model and available tools, which is precisely what makes it a policy surface rather than a runtime surface. That distinction is where the two execution models begin to diverge.
Why the Threat Profile Changes Fundamentally When the LLM Writes the Code
Palo Alto Networks' Unit 42 research documented something that anyone who has spent real time with autonomous coding agents will recognize: an LLM deployed as an autonomous agent successfully executed SQL injection, server-side request forgery, and unauthorized data exfiltration, attacks its chat-only counterpart consistently refused. The mechanism is structural. A chat interface refuses based on content policy. A code execution runtime refuses nothing; it runs what it receives.
That gap is the thing people underestimate. It is not a model alignment problem you can tune away. It is an architecture problem. Why exactly does this happen? Because the runtime makes no distinction between code a human wrote and code a model produced — it simply executes.
AI-generated code is untrusted code by definition. Veracode's 2025 State of Software Security report found that 45% of AI-generated code fails security tests. Any pipeline that runs LLM-produced code without isolation is running untrusted code at a failure rate that would be unacceptable from any other source.
The failure modes are not hypothetical. Claude Code reportedly wiped a user's entire Mac home directory through a trailing ~/ in an rm -rf command, accidental rather than adversarial, but the damage was identical to intentional destruction. Supply chain campaigns, including the Shai-Hulud campaign targeting npm packages used in AI agent workflows, exploit the fact that agents with network access install and run packages without inspecting them. CVE-2025-34291 in the Langflow platform allowed attackers to bypass authentication and execute arbitrary Python through a code execution path exposed remotely. LLM-generated patches introduce new security vulnerabilities in approximately 9.5% of cases even while fixing the original issue, per published research.
The structural reason code execution is a harder problem than tool call sandboxing: the LLM can write code that spawns subprocesses, modifies the filesystem, opens network sockets, or installs packages. None of that can be enumerated and denied in advance by a schema, because there is no schema. The interpreter accepts whatever the model produces. Blast radius in this model can escalate to full remote code execution on the host. The boundary between sandbox and host is not one factor in the security model; it is the security model.
The Isolation Technology Hierarchy Builders Are Actually Choosing From
The ecosystem has settled, at least for now, on three layers of isolation tooling. At the base are primitives: open-source virtualization tools like Firecracker, gVisor, and Cloud Hypervisor, run on your own infrastructure. Above that sit embeddable runtimes, middleware SDKs that wrap those primitives for teams that need sandboxing without building the underlying infrastructure. At the top are managed platforms that handle primitives, orchestration, scheduling, and scaling together.
The two dominant approaches at the primitive layer reflect a genuine engineering tradeoff, one I have watched teams relitigate more times than I can count. Firecracker microVMs give each workload its own kernel on hardware virtualization via KVM. A kernel exploit inside one VM cannot reach the host. Firecracker boots in roughly 125ms with approximately 5MB of memory overhead, and it is the current practical standard for untrusted code execution at scale. gVisor takes a different path: no hardware virtualization, but a userspace kernel called runsc that intercepts syscalls before they reach the host. Built by Google and used in Cloud Run and GKE Sandbox, gVisor adds 5 to 15 percent overhead on syscall-heavy workloads and near-zero overhead on typical coding tasks. Cheaper to start, but its isolation ceiling is lower.
GPU access separates them further as agent workloads grow more compute-intensive. gVisor's userspace kernel blocks direct PCIe passthrough. Firecracker's hardware virtualization path supports VFIO device passthrough, giving the sandbox near-native GPU performance. Teams building ML-heavy agent pipelines tend to discover this gap at an inconvenient moment, usually after they have committed to an architecture. That is not a knock on gVisor; it is just a constraint that the documentation does not surface prominently.
Standard containers using Docker share the host kernel with namespace isolation only, and kernel vulnerabilities remain exposed. NIST SP 800-190 is explicit that OS-level virtualization is not a security boundary sufficient for untrusted code execution. The industry has largely moved past debating whether to isolate. The live questions are which virtual machine monitor, which boundary, and how persistent state must be.
Resource limits require enforcement at the cgroup level, not the application level. Application-level limits can be bypassed by agent-generated code, and any sandbox that relies on application-layer enforcement has already lost the argument against a sufficiently confused or motivated model.
What Cold-Start Latency and Session Persistence Demand from Each Model
Tool call sandboxing imposes relatively modest latency requirements. The sandbox wraps a known function rather than an arbitrary runtime, and startup overhead is driven by the function's own execution time. Persistent, warm tool environments are often the right architecture: the calls are frequent, predictable, and short-lived.
Full code execution is a different problem entirely. Each invocation may spin up a fresh isolated environment, and if that takes ten seconds, the bottleneck in the agent workflow shifts from model inference to infrastructure. Published benchmarks give a useful range: Cloudflare Sandboxes report sub-50ms cold starts; Blaxel reports 25ms resume from standby; Firecracker itself boots in roughly 125ms; the better managed platforms target cold starts under 200ms. Below that threshold, sandbox startup is not the agent's bottleneck. Above it, latency compounds across every tool call in a long-running workflow in ways that are difficult to reason about until you are watching a job stall and trying to explain it to someone.
Statefulness is where the architectural debt becomes most visible. Traditional infrastructure imposes hard timeouts because its underlying model is synchronous HTTP: AWS Lambda hard-limits at fifteen minutes, Vercel at a few minutes. Code execution agents accumulate context across dozens of tool calls. Losing that state on timeout is not a degraded experience; it is a failed run.
Firecracker's snapshot-restore mechanism addresses this directly: pause a sandbox, preserve memory and filesystem state, resume in five to thirty milliseconds. Perpetual execution environments go further, breaking the timeout constraint entirely. The agent runs asynchronously inside a sandbox independent of any client connection; send input, disconnect, reconnect hours later, and the agent is exactly where it was. MCP's task primitive and Google's Agent-to-Agent (A2A) protocol both model tasks as durable state machines with status, artifacts, streaming, and idempotency. The runtime needs to match what the protocol already assumes, and most retrofitted infrastructure does not.
Concrete Sandboxing Requirements for Each Execution Model
For tool call sandboxing, the requirements cluster around policy rather than process containment. Each tool should expose only the operations the LLM is permitted to invoke; the schema is the policy surface. Tool results flowing back into the LLM's context window are the primary attack vector, so output sanitization is not optional. Network egress from tool environments should be restricted to the specific endpoints each tool legitimately needs. API keys and credentials should be absent from the tool environment by default, mounted explicitly and securely only for specific cases. Process-level or container-level separation is often sufficient, because the threat is policy violation, not arbitrary code execution originating from inside the sandbox.
For full code execution, the requirements are structurally different, and the gap is wider than it first appears.
Hardware-level isolation, a microVM or equivalent, is the non-negotiable baseline; container namespaces are not a security boundary against code the LLM wrote. The filesystem mount should be scoped to the project directory only, not the home directory, and destroyed after use. The Claude Code incident is a useful reminder of how mundane the failure can be: no adversary required, just a trailing slash. Each sandbox needs its own network namespace, because without network restrictions, agents freely install and execute supply-chain-compromised packages. Resource limits must be enforced at the cgroup level. Stateful snapshots should treat every major checkpoint as a resume point. And observability needs to be built into the runtime: every model call, tool call, and sub-agent step traced with timing, inputs, outputs, and cost, because when a long run fails at hour three, the trace is what you read.
These two models coexist in most real agent systems. The LLM invokes tools through a policy-scoped interface and also has access to a code execution tool running in a microVM. Each layer receives the isolation appropriate to its threat surface, and conflating them creates gaps in both directions.
How Purpose-Built Platforms Handle These Requirements Differently from Retrofitted Infrastructure
More than 80% of AI projects fail to reach production, and infrastructure mismatch consistently contributes to that failure. Teams that deploy agents on runtimes designed for traditional web workloads spend engineering time compensating for constraints that were never going to disappear: timeouts, statelessness, shared kernels. These are not configuration problems; they are design assumptions baked into platforms built for a different workload entirely.
The platform choices available in 2025 differ meaningfully on isolation model, persistence, and where the compute runs.
Daytona is built specifically for AI-generated code execution, with sub-90ms sandbox provisioning, stateful sessions with indefinite duration by design, and Docker-native compatibility that lets teams bring existing images without retooling. Its customer-managed compute model keeps data and cost control on the customer's side. SOC 2, HIPAA, and GDPR compliance are built into the runtime rather than layered on at the application level, and the codebase is open-source and auditable, which matters for regulated workloads where black-box execution services introduce a trust gap that cannot be absorbed.
Vercel Sandbox uses Firecracker-based microVM isolation and delivers competitive cold starts, optimized for frontend-adjacent workloads and shorter-lived execution; session persistence is not its design center.
Northflank is a managed platform with strong support for long-running sessions and complex multi-service deployments, with orchestration and scheduling as first-class capabilities.
Cloudflare Sandboxes offer sub-50ms cold starts and strong edge distribution but are not designed for stateful, long-running agent sessions.
It is also worth considering the customer-managed compute distinction, which tends to surface later than it should in procurement conversations, usually after the cost surprise. Teams running agent workloads on shared infrastructure cede data residency and cost predictability. A 10x cost jump from prototyping to staging is partly an artifact of shared infrastructure with unoptimized defaults, and by the time organizations address it, the re-architecture is painful. I have seen this play out enough times that I now flag it explicitly in early architecture conversations, even when it feels premature.
Enterprise compliance cannot be a premium add-on in this category. Agents executing AI-generated code against production data need SOC 2, HIPAA, and GDPR controls at the runtime level, not bolted on afterward. That this still needs to be said in 2025 is its own kind of commentary.
Choosing the Right Isolation Strategy Given Your Execution Model
Start with one structural question: is the LLM selecting from a defined function set, or writing code that runs in an interpreter? The answer determines the threat surface before any platform choice is made, and conflating the two leads to over-engineering in one direction and under-engineering in the other.
For tool call isolation, the relevant questions are policy-oriented. Is each tool's permission surface the minimum it needs? Are tool outputs sanitized before they re-enter the context window? Is network egress from tool environments scoped to specific endpoints? Are credentials absent from the tool environment by default?
For code execution isolation, the questions shift to the runtime layer. Is the isolation model hardware-level, a microVM or equivalent, rather than container namespaces? Is the filesystem mount scoped to the project directory only? Are resource limits enforced at the cgroup level? Does the sandbox support stateful snapshots for long-running work? Is cold-start latency under 200ms? Is the runtime auditable?
For systems that combine both models, which most production agent systems eventually do, apply tool-call policy controls at the interface layer and code-execution isolation at the runtime layer. These address different parts of the same agent's attack surface; they are not redundant.
The infrastructure choice is not static. As agents grow more autonomous and run longer, the demands on statefulness and isolation depth increase. The architecture that looks sufficient at prototype scale has a way of revealing its constraints precisely when the workload becomes consequential and rebuilding is most expensive. That raises an important question: not whether a given sandbox is adequate for today's agent, but whether its design can accommodate what that agent will need to do in six months, before the answer to that question is forced on you.


