Process jails and kernel isolation for untrusted agent code

Running AI agents inside Docker containers without giving them the keys to your NAS

Standard Docker containers share the host kernel. Every process inside a container makes syscalls directly to that kernel, separated only by namespaces and cgroups. That boundary is thinner than it looks, and LLM-driven agents behind it sit in a different threat model from a web server or a database.

The shared kernel problem

Docker namespaces give each container its own view of the PID table, network stack, and filesystem. They do not give it a separate kernel. Every container on the host talks to the same kernel instance, which means one exploitable kernel path puts every other container, every mounted volume, and every credential file reachable from the host at risk.

CVE-2025-31133, CVE-2025-52565, and CVE-2025-52881, disclosed in November 2025, made this concrete. All three are runc vulnerabilities. CVE-2025-31133 exploits mount race conditions against masked paths during container creation. CVE-2025-52565 uses a malicious container config to trigger the escape. CVE-2025-52881 operates through procfs writes. Together they affect all runc versions up to 1.2.7 and 1.3.x, which means every standard Docker deployment running an unpatched runc is exposed to host-level privilege escalation from inside a container. The OCI released fixes; patch and verify with runc --version before reading further.

Seccomp profiles and AppArmor policies narrow the syscall surface and restrict file access patterns, but they cannot close the basic gap. They are filters applied to a shared kernel, and a flaw in that kernel bypasses both. The same applies to Linux capabilities: dropping CAP_SYS_ADMIN and CAP_NET_ADMIN reduces the attack surface, but does not remove it. Namespace separation without kernel separation leaves a gap that no userspace policy can fully close.

AI agents make this worse. An OpenClaw-class agent running inside a standard container has tool-use capabilities: it can write files, spawn subprocesses, make outbound network calls, and read anything mounted into the container. If a malicious or misconfigured LLM output drives the agent to probe /proc, write to a masked path, or abuse a mount operation, it does so with the same runc attack surface as any other container workload. The difference is that an agent can discover and exploit that surface on its own, without tripping the sort of signatures that look for obvious human attack patterns. The nine Linux AppArmor kernel flaws disclosed in 2024, which affected an estimated 12.6 million systems, showed that even the access-control layer above the kernel can be bypassed by a determined local process.

Two-layer containment: microVMs behind Docker sandboxing for AI agents

The sensible response to a shared-kernel threat is a separate kernel. MicroVMs give each workload a dedicated guest kernel with a hardware-enforced privilege boundary between guest and host. Kata Containers does this using a full hardware VM per container group, backed by QEMU or Cloud Hypervisor. Firecracker does it with a stripped KVM-based microVM that boots in around 125ms. Docker Sandbox uses Kata to back each sandbox session with a microVM, which is how NanoClaw achieves its two-layer containment model: each agent runs in its own container, and that container runs inside its own microVM.

That setup gives two distinct privilege boundaries. The first is the container boundary: namespaces, cgroups, a minimal filesystem, no host mounts. The second is the hypervisor boundary: the guest kernel cannot issue hypercalls that the host kernel honours outside the defined VMM interface. A runc escape from the container reaches the guest kernel, not the host. A guest kernel exploit would still need to cross the hypervisor boundary to reach the host filesystem or the NAS.

Within that microVM, per-agent container scoping adds the process jail layer. Each agent gets its own container with a scoped filesystem root. No agent shares a writable volume with another. Temporary working directories live inside the container and are discarded when the agent session ends. No persistent volume is mounted unless the task explicitly requires it, and when one is, it is mounted read-only with a path scope that covers only the directories the agent actually needs.

Credential paths need to be kept out of any volume mount. Do not mount /etc, /root, or any directory that contains SSH keys, API tokens, or .env files into an agent container. Use Docker secrets or environment variable injection at the compose or Swarm level, scoped to the specific container, not a shared mount. The NAS share should never appear as a bind mount inside the agent container; if the agent needs to write output, write it to an intermediate path and move it out of the container through a controlled sidecar process that validates the content before touching the NAS.

gVisor versus Kata Containers: what you are actually choosing

Kata Containers uses hardware virtualisation. The guest kernel is a real kernel running in a VM. Syscalls from the container hit the guest kernel; the host kernel only sees VMM traffic. The overhead is real, around 100ms to 300ms boot time per pod depending on the hypervisor backend, but the isolation boundary is hardware-enforced.

gVisor takes a different approach. It intercepts syscalls in userspace using a Go-based kernel implementation called runsc. The container process never talks to the host kernel directly; it talks to gVisor’s Sentry, which then makes a limited set of calls to the host kernel on its behalf. The host kernel attack surface shrinks because most syscalls are handled in userspace. The cost is I/O overhead, typically 10 to 30 percent on disk and network operations, and syscall compatibility gaps for workloads that use obscure or kernel-specific interfaces.

For agent containment, the choice comes down to the threat model. If the main concern is a compromised agent exploiting a kernel vulnerability, Kata Containers gives the harder boundary because the guest kernel takes the hit, not the host. If the concern is reducing the host kernel’s exposure to agent-generated syscall traffic without VM boot overhead, gVisor is more practical. The NanoClaw Docker Sandbox architecture defaults to microVM-backed isolation, which means you get the Kata boundary for each sandbox session plus container-level scoping inside it.

Enforcing security outside the agentic surface

Docker sandboxing for AI agents handles runtime containment. It does not handle what happens before or after the agent runs.

Set --read-only on the container filesystem and add explicit --tmpfs mounts only for paths the agent writes to. Run the agent process as a non-root UID with --user set in the Dockerfile, not at runtime, so it cannot be overridden. Set --cap-drop=ALL and add back only what the specific workload provably needs. Apply a seccomp profile; Docker’s default profile is a starting point, but audit it against the agent’s actual syscall requirements and tighten accordingly. Set --security-opt no-new-privileges on every agent container without exception.

Network egress is a separate problem. An agent with unrestricted outbound access can exfiltrate data, beacon to external infrastructure, or make API calls outside the intended scope. Use a user-defined Docker network with no default internet access, and route allowed egress through an explicit proxy that logs and validates the destinations. Block direct access to the host network with --network set to the agent’s scoped network only.

Audit the volume mount list before every deployment. The NAS share, the host credential store, and any path containing secrets should not appear in docker inspect output for an agent container. If they do, the containment model has already failed before the agent runs a single tool call.

Related posts

Weekly Tech Digest | 06 Jul 2026

Stay updated with the latest in tech! This digest covers AI ethics, auto industry shifts, and the impact of politics on technology, exploring today's pressing issues.

wolfCOSE zero-allocation parsing in embedded C

wolfCOSE looks sensible only if you care about what your firmware actually has to carry. I like that, because on small targets the wrong crypto feature can cost more than the message itself, and there...

restic | v0.19.1

restic v0 19 1: safer FUSE mounts and mountpoint checks, robust backup source and exclude handling, clearer CLI JSON output, Windows SFTP deletion fixes