Skip to content
atlas

Container escape

Also known as: container breakout

An attack where code running inside a container breaks out of it and gains control of the host machine beneath it.

Draft - this entry has not been reviewed yet.

Formal

A kind of privilege escalation in which a process inside a container uses a flaw in the kernel or container runtime, or a too loose setting, to act outside its container with the host's rights.

In plain English

Like a guest in one hotel room who finds a loose wall panel and suddenly walks into the hotel's back office.

In practice

An attacker takes over a municipality's booking app, which runs in a container with full admin rights and the host's disks attached; one file written to the host lets them run code on the whole machine.

Why it matters

Many teams treat containers as walls between customers or programs; one escape turns a single weak program into control of every container on the host.

Technical deep dive

MITRE ATT&CK tracks the technique as T1611 (Escape to Host) under the Privilege Escalation tactic. Escapes fall into three families. Configuration escapes need no bug at all: a container started with --privileged (all capabilities, all devices, no seccomp or LSM profile) can mount the host's block device or load a kernel module; a bind-mounted /var/run/docker.sock or containerd socket lets the process ask the daemon to start a new privileged container with / mounted; hostPath volumes, hostPID or hostNetwork in a Kubernetes pod spec, or CAP_SYS_ADMIN on its own, open similar paths. The classic cgroup v1 release_agent trick (writing a host-path script into release_agent and triggering it when a cgroup empties) needs only CAP_SYS_ADMIN and a writable cgroupfs; CVE-2022-0492 showed a missing capability check made it reachable in some unprivileged setups.

Runtime escapes exploit the low-level runtime that sets up the container. CVE-2019-5736 let a malicious image overwrite the host's runc binary through /proc/self/exe when an operator ran docker exec; CVE-2024-21626 ("Leaky Vessels") abused a file descriptor to the host filesystem that runc leaked into the container, reachable through a crafted WORKDIR of /proc/self/fd/N. Kernel escapes use any kernel bug reachable from inside the namespace: Dirty COW (CVE-2016-5195), Dirty Pipe (CVE-2022-0847) and CVE-2022-0185 (a heap overflow in filesystem context parsing that needed CAP_SYS_ADMIN, obtainable inside an unprivileged user namespace) are well-known examples.

Defence is layered because no single control covers all three families. Kubernetes Pod Security Standards at the "restricted" level forbid privileged pods, host namespaces, hostPath and added capabilities, and require runAsNonRoot and a seccomp profile; admission controllers (Pod Security Admission, Kyverno, OPA Gatekeeper) enforce this. Keeping runc and the kernel patched closes known runtime and kernel paths; user namespaces make container root an unprivileged host user; read-only root filesystems remove persistence. For hostile multi-tenant workloads, gVisor or Kata Containers put a user-space kernel or a VM between the workload and the host kernel. Detection tools such as Falco watch for tell-tale syscalls: mounts, writes to release_agent, unexpected setns or shells spawned by runc.

A container escape differs from ordinary privilege escalation inside the container (becoming root in the container is not yet an escape) and from a VM escape, which requires a hypervisor bug and is far rarer. After escaping, the attacker typically harvests kubelet credentials and service-account tokens of every pod on the node, which is how an escape turns into lateral movement across the cluster.

What to learn first

Everything this builds on, foundations first.

  1. File system
  2. →Kernel
  3. →Operating system
  4. →Process
  5. →Container
  6. →Container image
  7. →Container runtime
  8. →Container escape

Relationships

Sources & further reading

Where this data comes from

This entry was drafted by an AI from the sources above and has not yet been checked by a person. Treat it as a starting point, and check anything important against the sources.

See the review queueSuggest a correction on GitHubThis term as JSON

Check yourself

Loading…

Atlas is in beta.