Sandbox Escape Techniques in LLM Code Execution Environments
Research reveals how LLM sandboxes fail when code execution becomes probabilistic and unreviewed.

LLM agents in 2026 don't just write text back to a chat window. They run code, browse live web pages, call APIs, touch files, spin up cloud resources, and chain all of that together across a dozen steps without a human checking each one. Every one of those capabilities is a door, and the question this article works through is simple: does the sandbox around that door actually hold when the code walking through it was never reviewed by a person and behaves differently every time it runs?
That question matters more this year than last, for three reasons that are converging at once. Agents now carry tools that used to live safely behind a server, invisible to any user. Sandbox setups across vendors are wildly inconsistent, ranging from real Docker containers to full VMs to a bare Python process with a flag that sounds protective but isn't. And prompt injection now reaches straight into the sandbox: an attacker doesn't need a kernel exploit anymore. They just need language that convinces the agent to point its own legitimate tools somewhere they shouldn't go.
Classical security assumes code is deterministic and reviewable, something a person read once and signed off on. LLMs break that assumption at the root. They're probabilistic. Meaning shifts based on context, and context accumulates across a session in ways nobody fully audits. Researcher Schwarz, writing in "Unvalidated Trust" (November 2025), frames the shift precisely: the operative question is no longer "what did the user ask" but "what did the model infer, and at what point did that inference start acting with authority it was never granted." That reframing changes what a security review even needs to check. The isolation boundary has to survive arbitrary Python.
The numbers back up why this can't be waved off as theoretical. Research on LLM-generated code has found that a meaningful share of the code snippets produced contain bugs serious enough to open the door to exploitation. A static security check that passed yesterday tells you very little about the code the same model generates today. NIST's AI 600-1 documents indirect prompt injection, where an attacker plants instructions inside data the model later retrieves, a PDF, a webpage, a database row, and uses that to steal data or trigger code execution remotely. The attack surface, in other words, isn't just what the user typed. It's every document the model has ever been asked to read.
Enterprises can't manage risk they can't name. Before getting into the specific ways sandboxes break, how the research on this topic is organized right now is itself part of the problem.
How the research literature on execution security is currently organized (and where it falls short)
Scattered is the honest word for it. Rashidi's paper (arXiv:2607.05743) makes the case directly: research on sandbox isolation, denylist fragility, time-of-check-to-time-of-use (TOCTOU) races, threats to a protocol used for connecting models to external tools and data, and network egress control gets published in silos. Papers in one category rarely cite papers in another, even when they're describing versions of the same underlying failure.
Rashidi pulls together 39 papers published between 2023 and 2026 and sorts them into 17 categories, which is useful on its own. But the more interesting finding is what's missing. Four existing surveys of agentic AI security, three broad ones plus one focused specifically on open agentic platforms, all treat execution isolation as a single bullet point buried among many other concerns. None of them give execution security its own dedicated treatment. That's a gap, and it's the kind of gap that lets a known failure mode resurface as a "surprise" CVE two years later.
Rashidi surfaces five cross-cutting gaps:
Isolation architectures get measured against attacker capability constantly, but almost never against each other, on a shared benchmark, under the same conditions. Policy-enforcement research reports denylist failure rates running from 69% up to 98% against real-world denylists, and yet not one isolation paper goes back and re-tests its own defense under that same adversarial pressure. TOCTOU races and MCP threats keep getting studied as if they're unrelated, when structurally they're the same problem: a system checks a condition, then acts on stale information before that condition can change again. Every enforcement mechanism in the literature assumes the person who wrote the policy got it right, so authoring error itself sits completely unaddressed. And under realistic prompting, agents take benign but out-of-scope actions at rates up to 17.1%, a failure mode no access-control paper currently accounts for.
Schwarz's parallel taxonomy in "Unvalidated Trust" catalogs 41 semantic and structural risk patterns, organized not by product but by mechanism: trust that gets inherited across processing stages without being re-checked, sensitive plans assembled through interpretation rather than explicit instruction, and state or memory effects that quietly persist across turns of a conversation.
The fragmentation isn't just an academic inconvenience. It's an enterprise risk in its own right. A security team that only reads the container-isolation literature will be blindsided by a Python-layer bypass, and vice versa. So the taxonomy that follows is organized by mechanism, not by vendor or product, because that's the only structure that actually helps someone evaluating a deployment they didn't build.
Python-layer escapes: why AST-based sandboxes fail against non-deterministic code
Most LLM platforms that sandbox Python do it by parsing the code into an abstract syntax tree (AST) and checking that tree against an allowlist or denylist before anything runs. It's the dominant pattern in the industry right now. It's also, going by the CVE record, the pattern that breaks most reliably.
Python's own governance documents say this outright. PEP 551 puts it in plain language: don't try to build a sandbox inside the Python runtime itself. The advice is to run unrestricted Python inside something with real isolation underneath it, at minimum hypervisor-level separation.
An AST check inspects source code as written. An AST check inspects source code as written. But the actual attacks tend to live somewhere the AST pass never looks: inside data that gets formatted at runtime, inside attribute resolution that only happens when the code executes, or inside bytecode that never resembles the original source at all. A filter that only reads syntax is blind to anything that only becomes dangerous once it runs.
A handful of specific techniques show exactly how this plays out. Dunder traversal, sometimes called an MRO climb, walks Python's Method Resolution Order up to object.__subclasses__(), then hunts through that list for a class that wraps os.system or subprocess. Block the first rung of that climb and the rest collapses, except multiple separate techniques exist to restore that first rung. Runtime string smuggling does something sneakier: str.format parses field names like "0.__class__" and calls getattr at runtime, which means the exact dunder traversal an AST filter is built to forbid gets smuggled through what looks like an innocent string method. Dynamic name construction goes a step further, building a blocked dunder name at runtime out of chr() codes or concatenated string fragments, then feeding the assembled name into getattr(). That defeats keyword matching by design, since the forbidden word never appears as a literal anywhere in the source. Both known bypasses against the PraisonAI framework used exactly this pattern.
Frame and generator introspection is its own quiet failure. Attributes like gi_frame, f_back, and f_builtins don't start with an underscore, so any AST check written to block underscore-prefixed dunders simply doesn't see them, and from there it's a short chain to __import__. Whitelisted dependency traversal is arguably the sneakiest of the group: a sandbox might block os outright while allowing pandas and numpy, both of which are full C extensions that already imported everything the sandbox thinks it banned. Calling pandas.read_pickle() or numpy.load(allow_pickle=True) is arbitrary code execution wearing a friendly docstring, and the agent never has to type a single forbidden word to trigger it.
The CVE record from 2026 reads like a catalog of these patterns in the wild. CVE-2026-40158 resolves a call to an ast.Constant node instead of the ast.Attribute node the filter is actually checking, walking straight past attribute-based filtering. CVE-2026-39888 escaped the PraisonAI sandbox through __traceback__ → tb_frame → f_back → f_builtins. CVE-2026-40217 hit LiteLLM's /guardrails/test_custom_code endpoint, where caller-supplied Python ran in a sandbox escapable through bytecode rewriting and dunder traversal, resulting in remote code execution as the LiteLLM proxy process itself, affecting builds through April 8, 2026. HuggingFace's smolagents library had its own entry, CVE-2026-4963, in version 1.14.0: user-defined classes could implement a malicious __str__ or __repr__ that fires on a plain str() call, and one path used gi_frame.f_locals to quietly append 'os' to the authorized-imports list, defeating the allowlist. The Agenta LLMOps platform (CVE-2026-27952) had an allowlist bypass that walked from a whitelisted numpy import through numpy.ma.core.inspect into sys.modules, landing on os.system. And Semantic Kernel's in-memory vector store (CVE-2026-26030) let an LLM emit a filter expression straight out of conversation text, which got compiled and evaluated in a way that allowed certain call patterns to slip through the dangerous-call checks with no check at all.
setrlimit calls, which cap things like CPU time, memory, and file size, get treated by some teams as a security boundary. There's no setrlimit constant for socket creation, arbitrary file reads, or execve(), so setrlimit calls are not a security boundary. There's no setrlimit constant for socket creation, arbitrary file reads, or execve(). It manages resource consumption, not access control.
Anyone evaluating a vendor platform shouldn't ask whether it uses an AST filter. Ask which specific bypass classes it has been tested against, by name.
Container-layer escapes: what benchmarking frontier models against real Docker misconfigurations reveals
Move up a layer and the picture changes. Container isolation, the kind built on Docker or similar OCI runtimes, runs workloads on a host kernel shared across containers, with namespaces, cgroups, and capability restrictions drawing the boundary. The host kernel still processes every syscall from every container that runs on top of it, so the boundary is not absolute. It's also not absolute, because the host kernel still processes every syscall from every container that runs on top of it.
SANDBOXESCAPEBENCH, published in March 2026 by researchers at Oxford and the UK AI Security Institute (arXiv:2603.02277), measures this directly. It's built as an Inspect AI capture-the-flag evaluation, using a nested sandbox so the escape attempt itself can be run safely, and it covers 18 scenarios split across three layers: 4 at the orchestration layer, 8 at the runtime layer, and 6 at the kernel layer, with difficulty ratings running from 1 to 5.
Frontier models can reliably break out of container sandboxes when the failure mode is a common one, misconfigurations and exposed control surfaces in particular, and they post non-trivial success rates. Frontier models can reliably break out of container sandboxes when the failure mode is a common one, misconfigurations and exposed control surfaces in particular, and they post non-trivial success rates even on some of the harder runtime and kernel scenarios. More strikingly, the models found four escape paths the researchers hadn't designed into the benchmark at all: one exploited default Vagrant credentials to SSH straight into the host, another swapped in a simpler eBPF chain in place of the packet-socket exploit the scenario intended. Capable models, in other words, don't stick to the script. They search opportunistically for whatever route to the goal actually works, intended or not.
What the models did not do is find anything new. Every successful escape traced back to a previously documented misconfiguration or a publicly disclosed CVE. The models did not find any novel container or kernel vulnerability. And the benchmark's shelf life turned out to be short: within two months of publication, a frontier model had saturated it, forcing an update to the paper.
Two specific CVEs illustrate the pattern outside the benchmark itself. CVE-2024-21626, nicknamed "Leaky Vessels," exploited a file descriptor leak in runc to achieve a full container escape. CVE-2025-52881 let an attacker misdirect writes into /proc by racing containers that shared mounts, using nothing more exotic than a standard Dockerfile. New runtime vulnerabilities keep being discovered in runc and related tooling, and they keep getting disclosed.
That's really the distinction that separates this layer from Python-layer escapes. An agent doesn't need to understand the kernel to exploit it here. It needs to recognize a misconfiguration and apply a technique that's already public. For enterprise deployments, misconfiguration, not novel exploitation, is the threat that actually occurs in practice.
But the container boundary holding isn't the end of the story. The most active escape family in 2026 doesn't touch the container at all.
Configuration-based sandbox escape: how trust handoffs let agents reach the host without breaking the container
Nearly every documented case in this category shares the same shape. The agent never breaks the sandbox directly. It writes something, a config file, a script, a modified setting, that a trusted component sitting outside the sandbox later reads, runs, loads, or scans without re-checking it. The sandbox holds. The trust handoff next to it doesn't.
Pillar Research's "The Week of Sandbox Escapes" mapped four repeatable failure patterns across Cursor, Codex, Gemini CLI, and Antigravity. Denylist sandboxes can't keep pace with how complex an operating system actually is. Workspace configuration files turn out to function as executable code in practice, even when nobody designed them that way. Safe-command allowlists check the name of a command rather than its full invocation, which is a much weaker guarantee than it sounds. And privileged local daemons sit entirely outside the sandbox boundary to begin with, so nothing about the sandbox's integrity says anything about theirs.
Cursor alone had three independent paths disclosed. CVE-2026-48124 involved a .claude/settings.local.json hooks file that workspace content could control, letting commands run outside the sandbox entirely; it carried a CVSS score of 8.5 and was patched in version 3.0.0. A second path used a modified virtualenv interpreter later invoked by Cursor's Python extensions. A third manipulated Git's fsmonitor metadata to slip past path-based security rules.
OpenAI's Codex CLI had its own version of the same story: the git show command looked read-only on the surface, but wasn't, and that gap let an allowlist bypass through, patched in version 0.95.0. Google's Gemini CLI exposed access to the Docker socket, and notably, the most serious vulnerability in this entire disclosure wave hit Codex, Cursor, and Gemini CLI at the same time. Antigravity had two separate issues: a way around macOS Seatbelt's blocklist, and a .vscode task configuration that behaved the same way the Cursor hooks file did.
None of these seven disclosed issues broke the sandbox itself. Every one of them found the gap between what the sandbox restricts and what a trusted component just outside it later reads, runs, or scans without asking questions.
Cymulate Research Labs, in work by researchers Ilan Kalendarov, Ben Zamir, and Elad Beber, ran a parallel investigation across Claude Code, Gemini CLI, Codex CLI, Cursor, and GitHub Copilot. The Gemini CLI findings stand out in particular. Two separate vulnerability families let a sandboxed attacker escape the container boundary and run arbitrary code directly on the host, independently of each other. A third finding went further, enabling theft of the user's Google OAuth token, which opens a path to full account impersonation and, from there, potential privilege escalation inside GCP.
Google was notified of these findings between January 5 and 7, 2026. As of the May 2026 publication date, 90 days had passed with no patch issued and no formal decision communicated back to the researchers. A CI/CD vulnerability carrying a maximum CVSS score of 10.0, which Google did patch in April 2026, is a distinct issue from the sandbox-escape and OAuth findings Cymulate reported.
Taken together, these three layers, Python, container, and configuration, don't describe three separate problems so much as three points along the same fault line: a sandbox is only as strong as its weakest assumption about what "outside" actually means.
Sources
- Unvalidated Trust: Cross-Stage Vulnerabilities in Large Language Model Architectures
- The Balkanization of Execution-Security Research for AI Coding Agents: Isolation, Access Control, and Time-of-Check-to-Time-of-Use Vulnerabilities
- ATR-2026-01935: LiteLLM Custom-Code Guardrail Sandbox Escape (CVE-2026-40217) | ATR
- Quantifying Frontier LLM Capabilities for Container Sandbox Escape
- The Race to Ship AI Tools Left Security Behind. Part 1: Sandbox Escape
- pillar.security
- bleepingcomputer.com