Beyond Git Worktree

Filesystem Isolation Strategies for Multi-Tenant Agent Workloads

Agents executing untrusted code require filesystem isolation that containers alone cannot provide.

Contributing Editor · · 13 min read
Cover illustration for “Filesystem Isolation Strategies for Multi-Tenant Agent Workloads”
Sandbox Infrastructure · September 20, 2026 · 13 min read · 2,990 words

Multi-tenant agent platforms are running into a problem that container-based isolation was never built to solve: an agent generates code at runtime, from a user's prompt, and then executes it. That single fact breaks the assumption every prior generation of SaaS isolation relied on. Filesystem isolation for these workloads has to work in layers, namespace controls, per-session mounts, and hardware-enforced boundaries stacked on top of each other, because no single layer contains the failure modes an agent introduces.

The adoption numbers explain the urgency. Industry forecasts cited by cloudnativenow.com put 40% of enterprise applications embedding task-specific agents by the end of 2026, up from under 5% in early 2025. Anthropic's State of AI Agents Report found 86% of organizations have already moved AI coding agents into production code, and 42% now trust an agent to lead development work with a human only reviewing after the fact. That's a fast curve, and it's arriving faster than the isolation tooling underneath it has matured, meaning adoption is outpacing the maturity of the tooling meant to secure it.

The reason this matters more for agents than for prior SaaS models comes down to a threat model inversion. Traditional multi-tenant software isolates at the application layer because the vendor controls what code runs, full stop. Agents flip that: the code executing on a given tenant's behalf was written moments earlier by a model responding to that tenant's prompt, and the platform never reviewed a line of it. Every tenant's workload becomes a plausible threat vector against every other tenant sharing the same infrastructure. Four attack surfaces have to hold simultaneously, compute, filesystem, network, and credential isolation, and a failure in any one of them produces a cross-tenant incident. OWASP's guidance for LLM applications, as summarized by blaxel.ai, says to treat the model as any other user. Code the platform never reviewed is untrusted by definition, no matter how well-behaved the vendor supplying the model has been historically. Bunnyshell.com reports that 80% of organizations have already run into risky agent behavior, including improper data exposure and unauthorized system access. In a shared execution environment, each of those incidents becomes a cross-tenant event rather than a single-tenant bug because the execution environment is shared across tenants.

None of this gets solved by one control. It takes layering, and to reason about where the layers should go, it helps to understand what each one covers, and where it stops.

What containers isolate (and the documented failures that define their ceiling)

Containers isolate through Linux kernel namespaces and cgroups: a separate process tree, an isolated view of the network, a scoped filesystem view, and hard limits on CPU and memory. What they do not do is give each workload its own kernel. Every container on a node shares the host kernel, full stop. Kubernetes' own documentation is blunt about this, describing containers as offering what blaxel.ai calls "a weaker isolation boundary" compared to hardware-based virtual machines.

That weaker boundary is not a hypothetical concern. CVE-2024-21626 let attackers manipulate a container's process working directory to reach the host filesystem through leaked file descriptors, and it touched Amazon ECS, Amazon EKS, and Docker deployments alike. CVE-2022-30137, known as FabricScape, enabled container escape and cluster takeover inside Azure Service Fabric, in infrastructure that sits underneath Azure SQL Database, Azure CosmosDB, and Power BI (Azure had disabled runtime access on those managed services beforehand, which is the only reason exploitation didn't reach them). CNCF's analysis of the runc breakouts disclosed in November 2025 concluded that any multi-tenant environment letting users define their own containers "could be at risk," per blaxel.ai's writeup.

Performance is its own failure mode here, not just security. Measurements cited by blaxel.ai show 5 to 50% performance degradation from co-located workload interference alone. A single runaway agent process doesn't just risk a security event, it becomes every neighboring tenant's latency problem, whether or not any exploit ever fires.

None of this means containers are the wrong tool everywhere. They remain entirely defensible for workloads where the platform controls what code executes, pre-defined functions, reviewed CI jobs, the usual automated build-and-deploy fare. They stop being sufficient the moment an agent is generating and running arbitrary code at runtime, because at that point the platform has no idea what it's about to execute. Containers remain part of the answer; the change is that they now sit beneath additional layers rather than serving alone. It's what has to sit above the namespace boundary to harden it, and for adversarial multi-tenancy, that means going below the kernel.

Hardening the container layer: what namespace tuning and seccomp profiles buy you

Some of this is old, well-documented practice that agent workloads simply make mandatory instead of optional. User namespace remapping ensures that "root" inside the container isn't root on the host, which shrinks the blast radius of a privilege escalation bug considerably. Dropping every Linux capability by default and disabling privilege escalation outright are both years-old recommendations that cloudnativenow.com flags as no longer negotiable once an AI agent is the one writing the code that runs inside the container.

Seccomp profiles do real work here too. Linux exposes over 300 system calls, and most agent workloads genuinely need only a small slice of them. A tightly scoped seccomp policy narrows what a compromised process can even attempt to do against the host kernel, which matters because the kernel is the thing every container on the node shares.

Resource limits double as a cross-tenant defense, not just a stability measure. Per-tenant CPU and memory cgroups stop a runaway agent from eating the shared pool, and rate limiting at the tool level keeps one tenant from draining a shared GPU or API quota that everyone else is also metered against. Network egress allowlisting closes off the most obvious data exfiltration path: route all agent traffic through an egress proxy, reject anything that isn't on the list, and the agent can reach its LLM endpoint and version control provider but nothing else, a pattern cloudnativenow.com highlights specifically. Giving each agent execution its own isolated Docker network, disconnected from every other agent's network on the same host, limits lateral movement even after a container is compromised. And scoping filesystem access to a single worktree, the one repository the agent is actually authorized to touch, keeps a file-editing tool from functioning as de facto admin access to the rest of the host filesystem.

All of that is real hardening. None of it changes the fact that the host kernel is still shared. A kernel zero-day walks straight past every one of these controls at once, because they're all userspace constructs sitting on top of the same kernel. A 2026 stress test referred to as Dirty Frag, documented by opencomputer.dev, makes the point starkly: on the container side, researchers went from unprivileged user to root in under two seconds. The VM side of the same test held, even when set up with deliberately weaker conditions: an unpatched guest kernel and no seccomp. The takeaway is architectural. The architecture is what counts: what matters is not which permissions the software grants, but whether the kernel is shared to begin with. That's the door that opens onto gVisor and microVM-based isolation.

gVisor: what a user-space kernel intercepts and where it still shares ground with the host

gVisor works by inserting a user-space kernel, called the Sentry, between the container and the host kernel, intercepting every syscall before it reaches the host. Instead of the 300-plus syscalls a normal container can throw at the kernel, only a minimal, vetted subset actually gets through; that is how the architecture works.

Where does that put gVisor on the isolation spectrum? The general consensus is that gVisor sits stronger than namespace-only containers but weaker than hardware-enforced VMs. That makes it a solid defense-in-depth choice for a lot of workloads, but not the right answer when the tenant on the other side of the sandbox is presumed adversarial. Northflank.com puts the performance cost at 10 to 30% overhead on I/O-heavy work, offset by fast startup times, a reasonable trade for compute-heavy AI jobs where a full VM would be overkill.

gVisor intercepts syscalls in userspace, but it still shares kernel boundaries at a deeper level than a true hardware VM does. A sufficiently novel kernel exploit can still find its way across. gVisor is not handing each workload a dedicated kernel, it's filtering what reaches the one kernel everyone shares.

Modal is a useful production reference here. It uses gVisor as its primary isolation layer, tuned for Python ML workloads, and has upstreamed support into SWE-bench, running the full 500-task Verified benchmark in 7 minutes according to modal.com. Native GPU support spans the T4 through the H200, and autoscaling from zero is part of the pitch. The tradeoff Modal accepts is gVisor-only isolation, with no microVM tier for teams that need something stronger. GPU workloads add their own wrinkle: gVisor intercepts CUDA calls through a component called nvproxy, which remains functional but still an active area of engineering in 2026, not a finished, settled implementation.

gVisor solves the problem of an unrestricted syscall surface well. It does not solve the problem of a shared kernel. For any workload where a kernel exploit is a live part of the threat model, the answer is a dedicated kernel per workload, and that means microVMs.

Firecracker microVMs: why a dedicated kernel changes the threat model, not just the configuration

Hardware virtualization through KVM changes the equation in a specific, mechanical way: each workload gets its own Linux kernel. An attacker now has to break out of the guest kernel and then break the hypervisor separately, two distinct boundaries instead of one shared surface everybody sits on top of.

Firecracker, built by AWS in Rust, is the reference implementation here. Figures from blaxel.ai put microVM boot time at roughly 125 milliseconds and memory overhead under 5 MiB per VM; northflank.com adds that a single host can support up to 150 VM launches per second. Those numbers matter because they're what make hardware isolation viable at agent-session scale rather than something reserved for long-lived, heavyweight VMs.

The Dirty Frag stress test referenced earlier makes the case concretely: the container side fell to root in under two seconds, while the VM side held even under a deliberately harder setup, an unpatched guest kernel, no seccomp, elevated starting privileges. The conclusion opencomputer.dev draws is architectural rather than incidental: the kernel simply isn't shared, so an entire class of privilege-escalation exploit has nowhere to go.

AWS's own Bedrock AgentCore reflects this thinking directly. Blaxel.ai reports that it runs each user session in a dedicated microVM with its own CPU, memory, and filesystem, a design choice from a team with every incentive to pick the cheaper option if it were defensible. It's a strong signal that microVM-per-session isolation is operationally workable at real scale, not just a lab result.

Firecracker by itself is a primitive, not a platform. Running it in production requires warm pool management, snapshot and restore tooling, and scheduler integration that Firecracker doesn't provide out of the box. Cold-starting a fresh sandbox pod for every incoming request adds latency nobody wants, so the common pattern, is to keep a pool of pre-booted idle pods warm, hand one out when a request lands, and release it back to the pool when the session ends. Daytona gets cold starts under 90 milliseconds this way, with a dedicated kernel, filesystem, and network stack assigned to every sandbox, emirb.github.io's figures show. Firecracker microVM isolation also underpins sandbox products built specifically for AI agents with Python and TypeScript SDKs, though session duration limits and the orchestration overhead of scaling past a handful of concurrent sandboxes remain real constraints teams have to plan around.

Firecracker answers how to provide the isolation primitive itself. How to run thousands of these microVMs through a standard Kubernetes control plane without hand-rolling a scheduler is what Kata Containers answers instead.

Kata Containers and hybrid isolation: how production platforms select isolation level per workload

Kata Containers wraps multiple VMMs, Firecracker among them, alongside Cloud Hypervisor and QEMU, and exposes microVM-grade isolation through standard container APIs. This is what makes hardware isolation operable inside Kubernetes without ripping out the scheduler and replacing it with something custom.

What production platforms actually do with this is pick isolation level per workload rather than applying one policy everywhere. Blaxel.ai describes the pattern this way: customer-facing agents that execute arbitrary, model-generated code run in microVMs, while internal background jobs and scheduled tasks running platform-reviewed code stay in hardened containers. The isolation level follows the threat model of the workload, not convenience or a one-size default.

Northflank is a concrete example of this hybrid approach running at scale, processing over 2 million isolated workloads a month, using both Kata Containers for microVM-level isolation and gVisor for lighter-weight cases, chosen per workload. It supports bring-your-own-cloud deployment across multiple major cloud providers, and bare metal, with unlimited session duration, GPU support, and OCI-compatible tooling. The logic is straightforward once stated: trusted workloads running code the platform itself wrote get containers with the hardening described earlier; untrusted workloads running agent-generated code get microVMs. That boundary isn't decorative, it maps directly onto which workloads can plausibly hurt a neighboring tenant.

The tradeoff is operational complexity. Kata adds an orchestration layer that raw Firecracker doesn't provide, requiring a heavier initial setup, but the payoff is Kubernetes integration that doesn't require a custom scheduler built in-house. The open-source ecosystem is still catching up to this pattern: Agent Sandbox, under Kubernetes SIG Apps, and Kata Containers itself are both building momentum, cloudnativenow.com's coverage shows, suggesting the tooling here is still maturing rather than settled.

Everything covered so far handles compute and kernel-level isolation. It does not touch a separate, parallel problem: what an agent's own tools can reach on the filesystem, independent of which sandbox the process happens to be running in.

Filesystem isolation as a distinct problem: why agent tool scoping is not covered by the compute boundary

Traditional web applications check permissions at the API layer, request by request. Agents don't work that way. An agent uses tools, a search tool, a read_file tool, to reach into file repositories directly, and if that search tool isn't scoped to the tenant's own workspace, the agent effectively has admin-level access to everything visible inside its execution environment, regardless of how well the compute sandbox around it is locked down. Fast.io frames this distinction directly: the compute boundary and the tool-scoping boundary are two different problems that happen to sit next to each other.

The fix fast.io describes is a workspace-per-tenant model. Every file operation carries a Workspace ID. Ingestion tags files with that ID immediately, on the way in. The retrieval-augmented generation pipeline stores embeddings in a namespace tied to that same workspace, and the agent's search tool is only allowed to query the namespace matching its current session's Workspace ID. Scoped tools function as an access control layer in their own right: an MCP tool like read_file has to be hard-limited to the tenant's root directory, and that's an application-layer control, sitting entirely apart from whatever compute isolation is running underneath. Both layers are required, and neither substitutes for the other.

Identity has to travel with every tool call, not just get checked once at session start. A tool call that arrives without tenant context attached is a gap in access control, full stop, no matter how the rest of the session was authenticated. Audit logging at the filesystem layer, every file access and every memory retrieval tagged with a tenant ID, is what fast.io identifies as the mechanism that makes a breach detectable and attributable after the fact rather than invisible. Daytona's model reinforces this at the infrastructure layer: each sandbox gets a dedicated kernel, filesystem, and network stack, per emirb.github.io's figures.

Multi-agent workflows introduce their own version of this risk, since delegation between agents can cross a workspace boundary that no one intended to open. A protocol referred to as AWCP, described in a paper at arxiv.org/pdf/2602.20493, formalizes temporary workspace delegation: a Delegator agent projects its workspace to a remote Executor agent, which then operates on shared files using its own unmodified local toolchain. The protocol matters because it decouples a lightweight control plane from the underlying transport, and it's built to integrate with MCP and A2A rather than replace them, which gives multi-agent systems a governed way to hand off file access instead of an implicit one.

Filesystem isolation, done this way, covers data at rest and data in use for the duration of a session. It does not cover what happens once that data has been embedded and stored for retrieval later; the next layer of risk lives there.

Vector database and embedding isolation: the semantic memory layer where cross-tenant leakage persists

Semantic search is approximate by design, and that's precisely what makes vector isolation a different kind of problem than filesystem isolation. Fast.io describes this failure mode: a similarity query can return a match belonging to the wrong tenant if the retrieval layer doesn't enforce filtering strictly, and mixing embeddings from multiple tenants inside a single index creates a latent leakage risk that becomes visible only when a query happens to expose it.

The OWASP LLM Top 10 for 2025 formally recognized this risk by adding a dedicated category, LLM08:2025, covering vector and embedding weaknesses, multi-tenant cross-leakage among them, and calling specifically for authorization to be enforced at the vector store itself rather than assumed to be handled somewhere upstream. That's the crux of it. A workspace-scoped filesystem and a hardened microVM don't help if the embedding index sitting behind the retrieval pipeline treats every tenant's vectors as one undifferentiated pool. Isolation has to be layered all the way through, compute, filesystem, and the semantic memory the agent draws on, because a single gap at any one of those layers is enough to turn a routine query into a cross-tenant disclosure.

Sources

  1. Multi-tenant AI agent isolation for SaaS platforms | Blaxel
  2. The New Multi-Tenant Challenge: Securing AI Agents in Cloud-Native Infrastructure
  3. Multi-Tenant AI Agent Architecture: Design Guide (2026)
  4. AWCP: A Workspace Delegation Protocol for Deep-Engagement Collaboration across Remote Agents
  5. What is Tenant Isolation? Multi-Tenant AI Security | Blaxel
  6. northflank.com
  7. northflank.com
  8. modal.com

More in Sandbox Infrastructure