Container Internals: Five Mechanisms That Define the Boundary
Containers differ from VMs in one critical way: they share the host kernel. VMs have a hypervisor separating guest and host kernel spaces. A container is just a process with specific Linux configurations applied. Five mechanisms define those configurations: namespaces control visibility (which processes, file systems, network, and user IDs the container sees), seccomp restricts which system calls it can make, LSM (SELinux or AppArmor) adds policy-based access hooks, capabilities split root privileges into granular units, and cgroups limit resource usage. Docker applies default policies for all five. Misconfiguring any one opens an escape path.
Kernel Vulnerabilities: Dirty Pipe as a Container Escape
Dirty Pipe (CVE-2022-0847), discovered by Max Kellermann, exploits a race condition between the page cache and pipe buffers. The splice system call moves data between file descriptors without copying. When a new pipe buffer is created, it incorrectly inherits the PIPE_BUF_FLAG_CAN_MERGE flag, allowing writes into read-only files by overwriting the page cache. Inside a container, the attack waits for runc to execute (triggered by kubectl exec), then overwrites runc’s binary through /proc/self/fd. The hash of the runc binary changes. Only the page cache is modified, leaving the host intact.
Misconfigurations: Privilege, Sockets, and Dangerous Capabilities
Misconfigurations are the most frequent escape vector and the easiest to fix. Running a container with the privileged flag gives root access on the host. Combining privilege with hostPID lets an attacker run nsenter to create a new process in the host namespace. Mounting sensitive host directories exposes SSH keys or init scripts. Exposing the Docker socket lets anyone inside the container spawn a privileged container with one API call. Scanning with Kubescape across 10,000 Kubernetes clusters found 37% stored credentials in config files and 23% ran containers with dangerous Linux capabilities.
CAP_BPF: Blinding eBPF-Based Security Agents
Many Kubernetes security agents, including Falco, Kubescape, and Tetragon, use eBPF maps to store monitoring state. These maps are global kernel objects accessible via the BPF system call. A container with CAP_BPF can delete entries from those maps directly. Schendel demonstrated this against Tetragon: after running a small C program to remove his process from Tetragon’s maps, reading /etc/shadow produced no alert. The security tool was effectively disabled. Most tools do not defend against map tampering. CAP_BPF is a dangerous capability to assign to any container.
Scanning and Policy Enforcement as Countermeasures
Fixing misconfigurations gives the best return on effort. Scan Kubernetes clusters continuously using Kubescape or similar tools. More than 100 controls appear across MITRE, NSA, and SOC 2 frameworks, but only 10-15 are critical to address. Kubernetes 1.30 added native validating admission policies that block privileged containers before they start. Seccomp profiles generated from recorded workload behavior block unfamiliar system calls, including splice, the syscall Dirty Pipe requires. Kubernetes has no default network segmentation, so adding network policies stops lateral movement after a breach. For kernel CVEs, patch quickly since exploits often lag behind public disclosure.
Container Runtime Vulnerabilities: Leaky Vessels and MicroVMs
Leaky Vessels (CVE-2024-21626), found by the Snyk research team, is a file descriptor leak in runc. The host’s cgroup file descriptor leaked inside the container. Setting WORKDIR in a malicious Dockerfile to the leaked path (/proc/self/fd/7) causes the container to start with the host file system as its root. Running cd ../ escapes to the host. About half of runc CVEs trace back to similar symlink and path-handling failures. MicroVMs such as Kata Containers address the shared-kernel problem by giving each container its own kernel via KVM, but escapes from microVM environments have also been demonstrated at Black Hat.
Q&A
Do most container misconfigurations require operators to actively turn off security? Containers start secure by default; developers under time pressure grant root rather than tuning each setting, which accumulates misconfigurations over time. ▶ Watch (43:44)
Does the Dirty Pipe exploit require targeting the first process inside a container? The payload just monitors for runc to execute and exploits it whenever that happens, so any triggered exec works. ▶ Watch (44:31)
Notable Quotes
number of lines we can see 234 processes Amit Schendel · ▶ Watch (5:47)
we’re going to overwrite the Ry binary Amit Schendel · ▶ Watch (21:06)
I guess no one is immune Amit Schendel · ▶ Watch (42:29)
Key Takeaways
- Containers share the host kernel, so kernel exploits with write primitives can break namespace isolation.
- Misconfigurations, especially the privileged flag and exposed Docker socket, are the most common escape paths.
- CAP_BPF lets a container tamper with eBPF maps, disabling runtime security agents like Tetragon.
- Seccomp profiles blocking unused syscalls prevent many kernel CVE exploits, including Dirty Pipe’s splice call.
- Add network policies to Kubernetes clusters; by default every pod can reach every other pod.
About the Speaker(s)
Amit Schendel is a senior security researcher at ARMO, the company behind the open source CNCF project Kubescape. He focuses on security research and low-level programming, with a specific interest in kernel drivers across Windows and Linux. He works in C++, Python, and Go, applying that background to problems at the intersection of cybersecurity, system-level development, and cloud technologies.