Runc Internals and Container Runtime Security Boundaries
Container workloads share the host kernel, making namespace isolation thinner than it appears.

Runc’s security boundary is the subject of this article, and its central constraint is simple. A container can have its own filesystem view, process tree, and resource limits while its code still has access to the host kernel. Understanding runc’s setup sequence explains both why hardening helps and why untrusted workloads call for a different isolation primitive.
What runc actually does before your container process starts
Runc is the OCI reference runtime. When containerd or Docker receives a start request, it constructs an OCI bundle containing a root filesystem and config.json, then hands execution to runc. Runc is the last privileged binary to run before the container process starts. Its brief setup phase establishes the restrictions under which that process will execute.
The sequence gives those restrictions their meaning. Runc creates Linux namespaces for mounts, process IDs, networking, UTS, IPC, and users, while the parent process applies cgroup resource limits. It then pivots the root filesystem, applies seccomp filters and AppArmor or SELinux profiles, drops capabilities, and executes the container entrypoint. Namespace creation, mount handling, and file descriptor management form an exploit surface before the application has done any work.
What, then, enforces the resulting restrictions? The container process runs with a reduced capability set, a kernel-enforced seccomp BPF filter, and configured mandatory access controls. Those controls constrain what its system calls can do, but do not place a separate kernel between the application and the host. OS-level virtualization differs from hypervisor-based isolation at precisely this point. The enforcement boundary is the shared kernel, where namespaces hide resources but do not intercept kernel execution.
Why sharing a kernel with the host is a thinner boundary than namespaces suggest
A private view of resources is not a private execution environment. Allowed system calls still enter the kernel that serves the host, so a flaw that can be exploited in an allowed handler can break through the namespace boundary. Seccomp reduces the available syscall set. It does not make the remaining handlers safe.
Dirty Pipe, CVE-2022-0847, illustrates that distinction. JFrog Security stated that splice, the syscall involved in the vulnerability, is allowed in Docker’s default seccomp profile. The filter therefore did not block that path. Assessing seccomp requires identifying which kernel operations remain reachable under the workload’s actual profile, even when seccomp is enabled.
Overly permissive device rules, or --privileged, can expose host block devices and open a path to mounting the host filesystem. CVE-2022-0492 exploited the cgroup v1 release_agent mechanism to execute commands on the host. Resource controls therefore need scrutiny beyond their limits on consumption.
Capabilities set what code can do through these interfaces: CAP_SYS_ADMIN allows operations that include filesystem mounts and namespace changes, while CAP_SYS_MODULE allows code to load kernel modules. Their reach is substantial, although exploitability also depends on the surrounding access controls and exposed resources. For trusted applications, a carefully restricted configuration can be an acceptable trade-off with minimal overhead. For untrusted code, the concern is that attacker-controlled execution still faces the host kernel directly.
How runc's setup sequence has been exploited across six years
In CVE-2019-5736, rated CVSS 8.6, a malicious container process could overwrite the host runc binary through /proc/self/exe. The exploit used a window in which runc’s file descriptor remained open inside the container’s mount namespace during execution. Subsequent containers on that node could then start through a compromised runtime.
CVE-2021-30465 moved the focus to mount handling. A time-of-check-to-time-of-use race let a container exchange a mount target with a symlink inside its root filesystem, redirecting a bind mount toward a host directory. Red Hat’s advisory described the result as the host filesystem being bind-mounted into the container. Although exploiting the race was complex, most Linux distributions rated it High or Important. Timing was part of the security boundary.
CVE-2024-21626, part of “Leaky Vessels,” exposed another transition error. Red Hat’s advisory described runc changing directories through /proc/self/fd/ before closing privileged host file descriptors while processing WORKDIR. A crafted WORKDIR instruction could leave the container with access to the host filesystem. The flaw depended on setup state that should not have survived into container execution.
On November 5, 2025, a SUSE researcher disclosed three further vulnerabilities involving mount manipulation and procfs redirection. One, CVE-2025-52565, targeted the mount from /dev/pts/$n to /dev/console, which occurred before maskedPaths and readonlyPaths protections were applied. It affected runc 1.0.0-rc3 and later. All three received fixes in runc 1.2.8, 1.3.3, and 1.4.0-rc.3 or later, and AWS released ECS and EKS security updates that day.
The operational record extends beyond named vulnerabilities. Security-relevant fixes to races and filesystem handling in libcontainer/ have also arrived as maintenance commits without CVEs. Operators therefore need parallel monitoring of the opencontainers/runc GitHub advisory feed, patch release notes, OSV.dev queries by Go module, pkg.go.dev/vuln, and the main-branch commit stream. Packaging complicates the response. Docker Engine, containerd, and CRI-O bundle runc, so updating an OS package may leave the invoked binary untouched. Operators should upgrade the parent engine and verify its bundled runtime afterward.
What runc's attack surface looks like from inside a running container
What host-facing interfaces remain reachable after initialization? That depends on the allowed syscall table, the capabilities the process keeps, the devices it can access, and any leaked descriptors. The container’s apparent filesystem boundary is only one part of that surface.
File descriptor leaks can leave references to host paths visible through /proc/self/fd/. Such access originates in a setup failure even when the container process later discovers it. Permissive device rules create a separate route by exposing devices such as /dev/sda, potentially allowing the host filesystem to be mounted. Dangerous capabilities can then amplify whatever access is available. CAP_SYS_MODULE permits kernel module loading, while CAP_SYS_PTRACE and CAP_DAC_OVERRIDE create risks where host processes or files are reachable.
Autonomous agents make this exposure harder to bound. An agent can generate code, install packages, invoke tools, and probe its surroundings repeatedly beyond a fixed application path. Emails, web pages, Slack messages, and documents bring untrusted input into what the agent runs. If the agent also has production data or credentials, a boundary failure threatens more than its immediate task.
This threat model combines runtime setup flaws, reachable kernel interfaces, and autonomous exploration of both. Falco and Tetragon can flag suspicious mount attempts, symlink creation over procfs files, or unexpected capability use. Those signals can reveal exploitation in progress. They do not replace the boundary whose failure made that activity possible.
Why hardening runc is necessary but not sufficient for untrusted code
Update to runc 1.2.8, 1.3.3, or 1.4.0-rc.3 or later, and enable user namespaces for all containers. The official runc advisory states that user namespaces block most of the most serious aspects of CVE-2025-31133 and CVE-2025-52881. They limit access to the procfs files that those attacks need. Running rootless further limits how much a vulnerability can affect.
Workload permissions should then follow actual requirements. Drop ALL capabilities in securityContext and add back only those required, such as NET_BIND_SERVICE for low ports. Set runAsNonRoot to true, allowPrivilegeEscalation to false, and readOnlyRootFilesystem to true. Enforce Kubernetes PodSecurityStandards at the “restricted” profile on production namespaces. Never run privileged containers in production, and treat a vendor requirement for --privileged as a red flag.
The remaining controls need equally deliberate treatment. Tune seccomp to the workload and apply AppArmor or SELinux protections. Use cgroup v2, whose design closes the cgroup v1 release_agent escape vector. Automate runc and containerd updates within a defined window after disclosure, and continuously audit versions across nodes. Those audits must identify the runtime actually invoked.
These measures meaningfully reduce reachable code and available authority. They cannot remove the shared-kernel constraint. A flaw in an allowed syscall handler can still offer a way to escape, even when the rest of the configuration is carefully set. For known, trusted workloads, the risk that remains can be acceptable. For user-supplied or AI-generated code, the next decision concerns the isolation primitive.
How gVisor and Firecracker change the isolation primitive for high-risk workloads
GVisor replaces direct access to the host syscall interface with a userspace kernel. Its runtime, runsc, directs application syscalls to the Sentry, which implements a substantial subset of the Linux kernel API in Go. The Sentry exposes roughly 240 syscalls to applications and uses roughly 100 host syscalls through a smaller interface. Filesystem operations pass through the Gofer process over 9P rather than giving the application direct host filesystem access.
That mediation has an execution cost. GVisor’s ptrace platform works on Linux hosts but adds significant overhead per syscall, while its KVM platform runs the Sentry inside a VM with lower overhead and requires host KVM access. I/O-heavy workloads incur meaningful overhead, whereas compute-heavy tasks see little. Google runs millions of gVisor instances daily. Google’s GKE documentation also names gVisor and microVMs as isolation options for Agent Sandbox.
Firecracker places a different boundary around the workload. Each microVM has its own Linux kernel running on KVM hardware virtualization, so compromising that guest kernel does not itself cross into the host or another microVM. This is a stronger separation from host kernel execution. Firecracker powers AWS Lambda and provides sub-second boot times with minimal memory overhead per microVM. Vercel Sandbox also uses a Firecracker microVM for each sandbox.
Kata Containers offers VM-level kernel isolation through OCI-compatible tooling, using QEMU, Firecracker, or Cloud Hypervisor as its backend. That model works for multi-tenant platforms where different customers’ agents share hardware but need separate kernels. Neither approach makes every component invulnerable.
The decision should follow the threat model. Hardened runc suits trusted code whose behavior is known, while agents that process untrusted external content need at least gVisor as their isolation primitive. When that input is combined with production data or credentials, Firecracker or Kata provides the required hardware boundary. Kubernetes RuntimeClass lets teams select runsc or Kata for specific pods without replacing the rest of the deployment model.
What purpose-built sandbox infrastructure adds beyond runtime choice
Agents are often stateful, singleton, and idle-heavy, with needs for pause, resume, and long-horizon execution that raw Kubernetes Deployments, StatefulSets, and Pods do not directly expose. The state that needs to persist includes conversation history, authentication tokens, and security context. Losing it at teardown is an application failure.
Persistence does not inherently weaken isolation. A persistent sandbox can maintain the same boundary as an ephemeral one when patching, isolation, and monitoring remain sound. Uncontrolled state is the risk. Provisioning speed poses a separate constraint, because workflows requesting fresh environments for each tool call become impractical when startup takes seconds. Sub-100ms provisioning supports responsiveness without requiring weaker isolation.
The relevant certification must cover the sandbox product itself, beyond any coverage of a vendor’s other services. HIPAA’s Audit Controls standard, 45 CFR 164.312(b), requires checks of activity on systems that contain PHI. SOC 2’s Processing Integrity criterion calls for evidence that processing is correct and controlled. The sandbox layer therefore needs evidence of its own.
Runtime observability supplies a different function from containment. A microVM boundary does not automatically record agent decisions, detect anomalous tool calls, or enforce policy across long-running sessions. Purpose-built infrastructure makes it possible to observe what runs, so failures can be found, policy can be enforced, and audit trails can be kept throughout. The system must preserve a suitable isolation boundary while controlling, updating, and explaining what executes inside it.


