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 running LLM-driven agents behind it is a different threat model entirely from running 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. What they do not give it is a separate kernel. Every container on the host talks to the same kernel instance, which means a single exploitable kernel path puts every other container, every mounted volume, and every credential file reachable from the host in scope.
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 fundamental 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 your 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 autonomously, without triggering EDR or DLP signatures that look for recognisable 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 sitting above the kernel can be circumvented by a sufficiently motivated local process.
Two-layer containment: microVMs behind Docker sandboxing for AI agents
The correct 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 architecture produces 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 of 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 explicitly excluded from 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 via 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 significantly 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 depends on your threat model. If the primary concern is a compromised agent exploiting a kernel vulnerability, Kata Containers provides a 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 the 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 the runtime containment problem. 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.
