Infrastructure Review Stack

User Namespaces and Rootless Containers for Isolation

Linux kernel isolation mechanisms protect AI agents from becoming a path to host compromise.

· 10 min read
Cover illustration for “User Namespaces and Rootless Containers for Isolation”
Secure Isolation Primitives · October 2, 2026 · 10 min read · 2,270 words

An AI agent running inside a container poses a different kind of risk than a web server or a batch job, because nobody wrote or reviewed the code it runs at the moment it runs it. A traditional containerized app executes logic a team built and tested in advance. An agent decides, mid-session, whether to run a shell command, install a package, call out over the network, or read a file that happens to contain instructions planted by someone else, and it can be steered somewhere nobody intended. Winninger's 2026 research states that once an agent has command-line access, defenses built into the prompt layer do nothing to stop indirect prompt injection, secret exfiltration, arbitrary script execution, or malware delivery. The defense has to sit at the machine layer, below the model, where behavior can be constrained regardless of what the agent decides to do. That this isn't hypothetical shows in amux's 2026 sandboxing guide, which documents CVE-2026-25592 and CVE-2026-26030: prompt injection inside Microsoft's Semantic Kernel agent framework escalated all the way to host-level remote code execution, because the agent's own tool-calling mechanism doubled as a shell. The failure modes that follow, filesystem damage, network exfiltration, privilege escalation, and resource exhaustion, run the gamut from careless accident to deliberate attack, and every one of them depends on the agent running unsandboxed. What follows is an account of the kernel mechanism built to contain exactly that risk, and a sober look at where it falls short.

What user namespaces do at the kernel level

The feature doing the real work here is the user namespace, and its job is identity remapping rather than resource restriction. Linux offers a handful of namespace types, and each one hides a different slice of the system from a process: PID namespaces hide the rest of the process tree, network namespaces hide interfaces and routes, mount namespaces hide the host filesystem, UTS namespaces hide the real hostname, IPC namespaces hide shared memory segments, cgroup namespaces hide the resource hierarchy, and time namespaces offset the clock a process sees. User namespaces behave differently from all of these. Instead of hiding a resource, a user namespace lets a process hold UID 0, full root, inside the container while the kernel maps that identity to an ordinary, unprivileged UID on the host machine. The remaining UIDs inside the container map into a subordinate range on the host, often somewhere around 100000 to 165535, and every one of those UIDs owns nothing on the host system.

OneUptime's Podman guide from January 2026 shows what this looks like in a running configuration: a user account gets 65,536 subordinate UIDs assigned to it, the operator's login UID becomes UID 0 inside the container by default, and the rest of that 65,536-UID block covers everything else the container process might need. Ojeda's analysis connects each namespace type to a specific risk an AI agent poses: the mount namespace limits what files the agent can even see, the network namespace cuts off exfiltration paths, the PID namespace stops the agent from signaling or killing other processes on the host, and the user namespace changes the entire calculus of an escape, turning "own the host" into "own nothing". That last point is the hinge the rest of this piece turns on. The other namespaces narrow what an agent can see or touch while it behaves normally. The user namespace is the one that determines what happens the moment it stops behaving normally.

How the UID mapping shrinks blast radius in practice

A user namespace does not make container escape impossible, but it changes what an escape is worth to an attacker. In a conventional rootful Docker setup, escaping the container is equivalent to becoming root on the host: the attacker can read any file on disk, kill any process, rewrite network configuration, and plant something that survives a reboot. In a rootless Podman container, that same escape lands the attacker at UID 100000 or a similarly mapped subordinate UID, an account that owns no files on the host, cannot bind a privileged port, cannot load a kernel module, and cannot touch another user's data. A rootful escape gives the attacker the machine; a rootless escape gives the attacker nothing.

OneUptime's Podman documentation frames Podman as a drop-in replacement for Docker that runs rootless by default, with no background daemon and no root privilege anywhere in its execution path; even the runtime socket it exposes does not hand an attacker a path to host root. Production systems already lean on exactly this property. The Hermes Agent architecture, cited in the research behind this piece, demonstrates this in production: the agent never SSHes into a normal Linux shell, but into /workspace inside a rootless container configured with cap_drop: ALL, so a successful break-in still has nowhere useful to go. API7.ai's analysis lays out what rootless operation buys concretely: a compromised process holds fewer host permissions, cannot reach host root through the runtime socket automatically, cannot access restricted devices or privileged ports, has a much harder time acquiring dangerous mounts or capabilities, and multiple services can run under entirely separate host identities rather than sharing one. None of that depends on the attacker failing to escape. It depends on the escape landing somewhere worthless.

The hardening layer that rootless alone does not provide

Rootless operation is necessary, but it is not sufficient. The protection it offers depends entirely on the container actually being configured the way it's assumed to be. amux's sandboxing guide lists the flags that complete the picture: --network=none to remove networking entirely, --cap-drop=ALL to strip every Linux capability rather than the default set, and --read-only to make the root filesystem immutable, with --security-opt=no-new-privileges appearing alongside them in the guide's hardened example. If any one of these flags is skipped, the rootless UID mapping remains true, but the container then carries more capability, more network reach, or more writable surface than the design assumes. A kernel vulnerability, an unsafe mount, an overly broad capability set, or a runtime misconfigured by default can each weaken the boundary independently of whether the UID mapping itself is correct.

There's a second gap that rootless containers were never built to close, and API7.ai's July 2026 research draws the line clearly: container privilege and API authorization are separate problems. A rootless container running a web service with broken object-level authorization can still leak one customer's data to another through completely ordinary application code, no escape required at all. The container boundary protects the host from the process. It does nothing to protect one tenant's data from another tenant's authorized-looking request. Low-numbered port binding, certain networking modes, storage driver quirks, and cgroup behavior differences also sit outside what a flag change guarantees, so testing the actual production topology matters more than trusting that rootless plus a few flags reproduces every property a rootful setup had.

The attack-surface paradox: user namespaces expose more kernel code than they hide

Here is the genuinely uncomfortable part of this story. The same feature that shrinks the consequence of an escape also hands unprivileged users a door into kernel code they could never reach before, and that code has not been especially safe. Enabling unprivileged user namespace creation measurably widens the kernel's exploitable attack surface, and it has produced dozens of CVEs over a multi-year span. A striking share of those trace back to one subsystem: nf_tables, the Netfilter packet-filtering code, which is complex, under constant development, and now reachable by ordinary users who previously had no path to it at all. One recent example lets a low-privileged local attacker corrupt page-cache contents and escalate to root through the xfrm-ESP subsystem, and that path explicitly requires unprivileged user or network namespace creation to work; a related variant through RxRPC is tracked separately as CVE-2026-43500.

The consequences of this tradeoff are not abstract. Ubuntu 24.04 LTS shipped with kernel.apparmor_restrict_unprivileged_userns turned on by default specifically to close off this class of exposure, and the decision broke a long list of software that depended on unprivileged namespace creation to function: bubblewrap, Chrome's sandbox, Electron apps, Flatpak, Steam, and, newly urgent in 2026, AI coding-agent CLIs including OpenAI's Codex CLI and Anthropic's Claude Code sandboxed Bash tool on Linux. A security measure meant to reduce risk from one direction ended up disabling the isolation tooling meant to reduce risk from another.

Edera's objection to the whole framing deserves to be stated in full rather than waved off, because it is the strongest challenge to everything argued so far: user namespaces were never designed as a security boundary. They were built as a mechanism to let unprivileged users create containers and builds, and the industry has since framed that mechanism as a security control it was never engineered to be. That's a fair reading of the history. But what if the objection and the practical benefit are both true at once, just answering different questions? The claim this piece makes is narrower than "user namespaces are a complete boundary." It is that they change what an escape costs an attacker. Even granting that an attacker reaches an escape through a user-namespace-gated CVE like the xfrm-ESP path above, landing as an unprivileged UID is still a better outcome than landing as root from a rootful container. Attack surface exposure and escape consequence are two separate axes, and a feature can lose ground on one while gaining ground on the other. Holding both of those truths at once, rather than collapsing them into a single verdict, is what a sober reading of this feature actually requires.

Where the shared-kernel ceiling requires a different tool

Every argument made so far assumes the host kernel itself holds. For a meaningful category of workloads, that assumption is the weak point, and no amount of namespace configuration changes it. Containers of any kind, rootless or not, share the host kernel, and a kernel exploit can carry an attacker straight through the container boundary regardless of how the UIDs are mapped; NIST's own guidance notes that containers do not offer as clear-cut a security boundary as virtual machines, precisely because of this shared kernel. For workloads where the executing code should be treated as fully adversarial, multi-tenant sandboxes, or AI agents processing inputs nobody has vetted, that shared kernel is a ceiling user namespaces cannot raise. Raising it takes a hardware boundary instead of a software one.

Firecracker, the microVM technology that powers AWS Lambda, offers one version of that boundary: hardware virtualization with startup times under 150 milliseconds and memory overhead under 5 megabytes. That hardware boundary closes off entire categories of kernel-based attack that no amount of user-namespace hardening touches, because the attacker never reaches the host kernel in the first place. Kata Containers takes a related approach from the other direction, wrapping each container in its own lightweight VM so the workload keeps the familiar container interface while running against a separate kernel per workload. A hardened rootless container is sufficient for most AI agent workloads, and for workloads involving untrusted code or multiple tenants sharing infrastructure, pairing containers with gVisor or moving to Firecracker is the sounder call.

How production agent tooling implements these primitives today

The theory above appears, with real variation, in tools engineers run every day. OpenAI's Codex CLI ships with sandboxing turned on by default rather than left as an opt-in: Seatbelt on macOS, a combination of bubblewrap, Landlock, and seccomp on Linux, and restricted tokens on Windows, with three selectable modes, read-only, workspace-write, and danger-full-access. amux's guide calls this the strongest built-in sandbox among the developer CLIs it surveyed. Anthropic's Claude Code, as of version 1.3, takes a narrower approach with its Sandboxed Bash tool: Seatbelt handles isolation on macOS, bubblewrap handles it on Linux and WSL2, and both constrain bash commands along with their child processes. The gap is what sits outside that tool. File operations like Read, Write, and Edit, along with MCP servers and hooks, run with the full permissions of the Claude Code process itself, untouched by the sandbox. Anthropic's answer is an opt-in package, @anthropic-ai/sandbox-runtime, which wraps the entire Claude Code process, Seatbelt on macOS, bubblewrap plus seccomp on Linux, and takes its filesystem and network allowlists from a settings file at ~/.srt-settings.json.

Linux Landlock offers a different kind of fallback: an unprivileged filesystem and network LSM that needs no root and no namespace creation at all, and it sidesteps the Ubuntu 24.04 restriction on unprivileged user namespaces described earlier. Codex CLI uses it as a supplementary layer on Linux, with bubblewrap remaining the default backend. A research prototype called Sandlock, described in a May 2026 paper, points toward where some of this may be headed: it splits enforcement between a static policy compiled directly into kernel-enforced rules and a narrow supervisor that handles decisions only runtime context can resolve, covering filesystem, network, IPC, and syscall policy without requiring root, cgroups, container images, or mandatory namespaces at all, adding roughly 5 milliseconds of startup overhead while running Redis at bare-metal throughput. The friction point every one of these tools has to work around is the same one raised earlier: Ubuntu 24.04 LTS sets kernel.apparmor_restrict_unprivileged_userns=1 by default, and that single setting breaks bubblewrap-based isolation outright. The tools built to keep agents contained and the kernel setting built to keep the host safe are, at this moment, working against each other on one of the most widely deployed Linux distributions in production. That collision, more than any single CVE or any single sandbox flag, is the clearest sign that the isolation stack for AI agents is still being built in public, one patched assumption at a time.

Sources

  1. How to Run Rootless Containers with Podman
  2. AI Agent Sandboxing in 2026: Docker, E2B, Firecracker, gVisor, Modal & Daytona Compared — amux
  3. Rootless Containers Do Not Replace API Security - API7.ai
  4. Namespaces: The Operating System Feature AI Agents Were Waiting For — Joche Ojeda
  5. Steerability via constraints: a substrate for scalable oversight of coding agents
  6. Linux User Namespaces: 262% More Kernel Attack Surface
  7. Three bypasses of Ubuntu's unprivileged user namespace ...
  8. User Namespaces and uid Mapping - Linux Kernel Internals

More in Secure Isolation Primitives