Est.

Sandbox Session Timeouts and Cleanup Policies

Setting timeout policy wrong costs money, leaks resources, and creates security exposure.

Editor at Large · · 13 min read
Cover illustration for “Sandbox Session Timeouts and Cleanup Policies”
Sandbox Performance and Lifecycle · September 21, 2026 · 13 min read · 2,822 words

Sandbox lifecycle policy is not a housekeeping detail. Sandbox lifecycle policy decides how much a company pays for idle compute, how long a compromised credential stays live, and whether a stuck container ever gets torn down. G2's 2025 AI Agents Insights Report found that 57% of companies now have AI agents running in production. This piece walks through what a sandbox's lifecycle actually involves, why three common workload shapes each demand different timeout logic, and where enforcement quietly fails, starting with a real bug in Kubernetes' own agent-sandbox project.

Most teams treat timeout as a single dial they set once and forget. That's the wrong model, and it's why timeout policy that gets set once and forgotten raises runaway compute cost, resource leaks, and security exposure as the default outcome rather than the exception. Runaway cost happens when an idle or zombie sandbox keeps billing without doing anything useful. Resource leaks happen when an environment never hits a terminal state, so nothing ever reclaims it. Security exposure happens when a stale sandbox sits there holding credentials, filesystem state, or live network access well past the point where its task finished. None of these are edge cases. They're what happens by default when timeout and cleanup get treated as an afterthought: enforcement infrastructure, sitting in the same category as egress filtering and identity scoping.

What a sandbox's lifecycle consists of and why "just set a timeout" misses most of it

A sandbox doesn't just exist or not exist. It moves through a typed sequence: create, ready, active, idle, suspended or paused, deleted. Each transition is a policy decision, not something that happens automatically because a clock ran out. Treating the whole lifecycle as one on/off switch is where most timeout logic falls apart before it even meets a real workload.

The control plane's job is to expose the right operations, create, status, exec, pause, delete, and enforce policy at each of those transition points. Northflank's guidance for AI agent infrastructure recommends that the control plane persist a run ID, an owner, an expiry, and a policy version before it even provisions the sandbox, though Northflank frames this as an application architecture recommendation, not something a platform hands you for free by default. Plenty of teams assume the platform is tracking ownership and expiry on their behalf. Plenty of platforms aren't.

A TTL only fires when a sandbox reaches a terminal state. If that state is missed, the TTL sits there counting down toward nothing; that is the single most common reason "just set a timeout" fails in production. Idle detection is a separate problem entirely, one that requires tracking actual activity rather than wall-clock time since creation. Suspension preserves state but still consumes storage, so it isn't free, and deletion is the only operation that fully reclaims resources. Cleanup of an abandoned environment, one that never gracefully exited, is its own policy path, distinct from what happens when a task finishes normally.

The real policy surface is wider than one number. The real policy surface includes a hard TTL, an idle or inactivity timeout, a cap on how many sessions can run at once, an expiry on snapshots and stored state, and the relationship between restart behavior and cleanup triggers; the Kubernetes section below shows this relationship breaking in a very specific way. Three workload shapes, ephemeral, stateful, and long-running, each need this surface configured differently.

The three workload shapes and the timeout model each one requires

Ephemeral sandboxes exist to run one task and disappear. The right model is a hard TTL set at creation, paired with an exec timeout, and teardown the moment the sandbox hits a terminal state: success, failure, or timeout. The TTL works like a circuit breaker, an absolute cost ceiling, and teardown on exit costs nothing extra to run. The failure mode with ephemeral sandboxes is almost always a TTL set too generously, so a sandbox that finished its task ten minutes ago is still sitting there holding credentials and filesystem access it has no further use for.

Stateful sandboxes need the opposite instinct. These handle multi-step work where state has to survive between invocations, so a hard TTL is the wrong tool: it kills a session mid-workflow just because a clock ran out. Idle or inactivity timeout is the right primitive here instead, suspending the sandbox after a set period of no network activity rather than a fixed wall-clock duration. Blaxel suspends sandboxes to standby after 15 seconds of network inactivity. Cloudflare Sandboxes, which reached general availability on April 13, 2026, default to sleeping after 10 minutes of inactivity, with configurable settings for teams that need something looser. What "suspend" actually preserves, filesystem, memory, running processes, depends entirely on the platform's snapshot model, and that's a detail to check, not assume. There's a real cost tradeoff buried in here too: idle compute time, snapshot storage, and the cost of a cold rebuild from scratch are three different price points, and the right policy depends on which of those is cheapest for the workload in question.

Long-running sandboxes, the kind doing multi-hour or multi-day agent work, run into a different constraint: the active session cap. A 1-hour cap cuts off a long-running agent mid-task without warning. Even a 24-hour cap can still truncate work that spans multiple days. The right approach here is a hard lifetime ceiling acting purely as a cost backstop, paired with a retention policy generous enough to actually outlast the task it protects.

The Kubernetes zombie-sandbox problem: how a missing restart policy silently defeats cleanup

Diagram: The Kubernetes Zombie-Sandbox Failure Chain. Visualizes: Show the step-by-step mechanism by which omitting restartPolicy in Kubernetes agent-sandbox silently defeats TTL-based cleanup.

This bug class is the clearest proof that a lifecycle policy correct on paper can fail completely in production. In the Kubernetes sigs.k8s.io/agent-sandbox project, omitting restartPolicy causes Kubernetes to default it to Always. That default quietly defeats TTL-based cleanup, and it does so without throwing a single error or warning.

Walk through the mechanism step by step. When restartPolicy is left unset, it defaults to Always. Operators relying on TTLSecondsAfterFinished to reclaim sandboxes get no cleanup at all, because the sandbox never reaches a Finished state, and a TTL that never sees a terminal state never fires. Two failure modes follow directly. First, the zombie VM: an agent finishes its work, the container exits, and restartPolicy: Always immediately restarts it. The sandbox never reports Finished: True, so the TTL clock never starts, and the VM sits there consuming CPU and memory until someone manually deletes it. Second, and arguably worse: CrashLoopBackOff with no way out. An interactive container that panics on startup gets caught in an infinite restart loop under Always, never reaching a terminal state, never getting cleaned up, and burning resources the entire time it loops.

This isn't a hypothetical concern. GitHub issue #1577 in the agent-sandbox repo documents the empirical validation: a configuration using ShutdownPolicy: Delete with a TTL of 10 on a kata-qemu pool produced 11 or more stuck VMs per node. The fix is straightforward once someone knows to look for it: set restartPolicy: "Never" so the container stays in a terminated state on exit, which lets TTL-based cleanup fire the way it was supposed to all along. Documentation clarifying the restartPolicy-TTL interaction merged into the project on September 10, 2026, via PR #1587.

The lesson generalizes past this one project. Cleanup policy and restart semantics interact in ways that aren't obvious or well-documented by default, so any team inheriting a Kubernetes configuration from someone else should audit restartPolicy specifically before trusting that TTL-based cleanup does anything. That's also the argument for a hard deadline set independent of terminal-state detection, as a secondary safeguard. That's the circuit breaker that catches exactly the case where a sandbox never reaches the terminal state its TTL depends on.

Two-phase idle lifecycle management as the production-ready pattern

Diagram: Two-Phase Idle Lifecycle: Suspend First, Delete Later. Visualizes: Illustrate the two-phase sandbox lifecycle model that separates suspension from deletion, each on its own independently tunable timer.

Long-lived sandboxes, browser-based IDEs, notebooks, persistent agent workspaces, create a real tension. Keep them running while idle and they waste money doing nothing. Delete them the moment they go quiet and rebuilding becomes expensive and slow. A binary run-or-delete model doesn't fit this workload class, and that gap is what the Kubernetes agent-sandbox project's IdleLifecyclePolicy (PR #1160) was built to close.

The model splits into two phases, each with its own independently tunable timer. Phase one is auto-suspend: a running sandbox suspends itself after a configurable idle timeout, with the controller tracking activity through a status.lastActivityTime field rather than guessing from wall-clock time. Phase two is deferred deletion: once suspended, the sandbox sticks around for a separate, configurable retention period before it's actually deleted. Splitting these into two independent timers is the whole point. The cost and safety tradeoffs at each phase differ, and locking both to the same clock throws that flexibility away.

Last activity time is the load-bearing primitive the entire two-phase model rests on, not creation time, not last-request time in some generic sense. If a platform can't track it accurately, neither phase behaves correctly, full stop.

Blaxel, Cloudflare, and other platforms teams already run apply this pattern in one form or another. Blaxel moves sandboxes to standby after 15 seconds of inactivity and can hold them there indefinitely at zero compute cost, billing only for snapshot storage during standby. Cloudflare Sandboxes sleep after 10 minutes of inactivity by default, with a configurable keepAlive setting for tasks that need more slack. The specific thresholds differ by design, since a 15-second window suits a highly interactive agent in a way it never would a long batch job. But the two-phase architecture, suspend first, delete later, on separate clocks, is the structure that keeps recurring.

Applying this pattern well means configuring three things on purpose rather than accepting whatever ships by default. An idle threshold that actually matches the workload's rhythm matters, because a threshold tuned for interactive use will suspend a batch job that's simply thinking between steps. A retention period needs to be long enough that a paused long-running agent doesn't get deleted before it has a chance to resume. And a hard lifetime ceiling, set independently of any idle detection, acts as the backstop for the pathological case where the state machine itself breaks.

How isolation depth affects what cleanup must accomplish

Cleanup means something different depending on how deep the isolation boundary actually goes. Stronger isolation means more of a workload's state sits inside a boundary that deletion can fully reclaim in one step. Weaker isolation means cleanup has to actively verify nothing leaked out to the host, because deletion alone doesn't guarantee that.

Standard containers sit at the weak end of this spectrum. They share a kernel with the host, so a compromised workload may have already touched host-level state that deleting the container does nothing to reclaim. Cleanup here has to include host-level verification in addition to a container teardown. gVisor improves on this by running a user-space kernel layer that limits direct access to the host kernel, making cleanup of the container boundary meaningfully more complete, though host filesystem mounts still need explicit teardown rather than an assumption of cleanliness. Firecracker microVMs go further, giving each workload a dedicated kernel with hardware-level isolation, so deleting the microVM reclaims a genuinely clean boundary. Firecracker boots in around 125 milliseconds, carries under 5 MiB of overhead per VM, and supports up to 150 VMs per second on a single host, numbers that matter because they show this isolation depth doesn't cost a crushing performance penalty. Kata Containers deliver VM-level isolation through the standard Kubernetes CRI interface, and Northflank reports processing over 2 million isolated workloads monthly using Kata Containers alongside gVisor. Sysbox offers VM-level isolation without the overhead of hardware virtualization, mapping root inside the sandbox to an unprivileged user on the host, so deletion doesn't leave elevated host-side state hanging around. WebAssembly sits furthest along this spectrum: isolation is enforced at the instruction level inside a linear memory space, and there's no host memory access path to verify or clean up, because the boundary is structural rather than something a policy has to enforce after the fact.

Why does isolation depth matter more now than it might have two years ago? Frontier models' success rate on apprentice-level cybersecurity tasks climbed from under 10% in late 2023 and early 2024 to roughly 50% by 2025. A sandbox designed around what models could do at the earlier end of that range risks underestimating what a compromised sandbox can attempt before any cleanup policy has a chance to fire. In runc versions 1.1.11 and earlier, a crafted WORKDIR value could point outside the container and into the host filesystem, the concrete mechanism behind CVE-2024-21626, known as Leaky Vessels. Cleaning up the container after the fact does nothing to reclaim exposure that already happened on the host side.

So cleanup aggressiveness, how fast it fires and how completely it verifies, should scale with isolation depth rather than run on one policy across every sandbox type a platform offers. A microVM that deletes cleanly by construction can afford a short retention window without much second-guessing. A shared-kernel container earns more suspicion before anyone calls it clean.

The credential and network exposure window that timeout policy directly controls

Every second a sandbox keeps running after its task is done is a second its credentials, its network access, and its filesystem state stay live and, in principle, exploitable. That's the exposure window, and timeout policy is the lever that controls how wide it opens.

A sandbox provisioned with scoped API keys or cloud credentials holds onto them right up until it's deleted, no sooner. A sandbox provisioned with scoped API keys or cloud credentials holds onto them right up until it's deleted, no sooner. A zombie sandbox, the kind the Kubernetes restartPolicy bug produces, holds those credentials indefinitely, since nothing ever tells it to let go. Network access works the same way: an agent sandbox with permissive egress rules that stays alive past task completion keeps that outbound access open, and the idle period is exactly the window during which exfiltration or a callback to an external server becomes possible.

An agent writing a Python script has no legitimate reason to reach an unknown IP address over port 443. The sane default is no outbound network access at all, with an explicit allowlist for what's actually needed, deny-by-default egress as the companion principle. Teardown, when it happens, closes that allowlist along with everything else.

The ZombAIs case, documented by Johann Rehberger on embracethered.com on October 24, 2024, shows what this looks like when it fails end to end. A browsing agent without a sandbox executed a malicious payload it encountered, ran chmod +x on it, and connected out to an external command-and-control server. The entire attack chain depended on two things being true at once: the agent had persistent network access, and nothing enforced a lifetime policy that would have torn the environment down before the payload could execute and phone home.

The actual policy levers here work in combination, not in isolation. A short idle timeout shrinks the credential exposure window directly. A hard TTL puts an absolute cap on it regardless of activity. A deny-by-default egress rule limits what an attacker can accomplish within whatever window remains, even a short one. None of these substitute for each other. Timeout policy and network policy are complementary layers of enforcement, and tightening one without the other still leaves a real gap.

What platform-level lifecycle defaults look like across the ecosystem

The abstractions above only matter to the extent a platform actually enforces them, so it's worth looking at what ships as default behavior.

Blaxel runs sandboxes as microVMs and moves them to standby after 15 seconds of network inactivity. Standby duration is indefinite at zero compute cost on Tier 2 and above, though starter tiers enforce their own TTL limits, and billing during standby covers only snapshot storage. Resume comes back in under 25 milliseconds, with filesystem, memory, and running processes intact from before suspension. On compliance, Blaxel holds SOC 2 Type II, ISO 27001, and a HIPAA BAA, and it's named as one of seven sandbox providers in the OpenAI Agents SDK as of an April 15, 2026 update.

Beyond the standby behavior, active session caps run 1 hour on the Hobby tier and 24 hours on Pro. Blaxel sandboxes resume from standby in under 25 milliseconds, with filesystem, memory, and running processes intact. No compliance certifications attach to this particular tier structure.

Set side by side, these defaults are the concrete expression of everything covered above. A short inactivity window limits exposure, a suspend phase stays cheap to hold and fast to resume, and a hard session cap works as the cost backstop when nothing else catches a runaway sandbox first. The specific thresholds will keep shifting as platforms compete on resume latency and idle-detection precision, but the underlying shape, detect activity, suspend cheaply, cap hard, delete completely, is what separates a lifecycle policy that actually enforces something from a timeout number nobody ever goes back to check.

Sources

  1. What infrastructure do AI agents need to run code safely? | Blog — Northflank
  2. Best Code Execution Sandboxes for AI Agents in 2026 | Blaxel
  3. feat: add idle lifecycle policy for sandboxes by natifridman · Pull Request #1160 · kubernetes-sigs/agent-sandbox
  4. augmentcode.com
  5. github.com

More in Sandbox Performance and Lifecycle