In February 2019, container security researchers disclosed CVE-2019-5736, a vulnerability in runc — the low-level container runtime that underpins Docker, containerd, CRI-O, and Kubernetes — that allowed a malicious or compromised container to overwrite the host runc binary and execute arbitrary code as root on the host itself. It was one of the first widely publicized true "container breakout" bugs, and it fundamentally changed how the industry thought about the trust boundary between a container and the host that runs it. For anyone operating multi-tenant Docker or Kubernetes infrastructure, CVE-2019-5736 remains a foundational case study in why the container runtime layer deserves the same scrutiny as the kernel itself.
What CVE-2019-5736 Actually Does
runc is the reference implementation of the OCI (Open Container Initiative) runtime spec — the component that actually creates namespaces, cgroups, and ultimately calls execve() to start the process inside a container. To start or attach to a container process, runc briefly re-executes itself by opening /proc/self/exe, which is a symlink the kernel maintains to point at the currently running binary — in this case, the host's runc executable.
Researchers Adam Iwaniuk and Borys Popławski (with the issue independently identified by Aleksa Sarai of SUSE, the runc maintainer, and Yuval Avrahami of Twistlock) found that a malicious container image could win a race condition against this behavior. By crafting a container whose entrypoint is a binary that behaves like an interpreter (for example, replacing #!/bin/sh with a symlink back to itself), an attacker could trick a docker exec operation — or an initial container start into a specially prepared image — into causing the host to open a file descriptor to the container's malicious binary while runc still believed it was referencing its own executable. The container process could then obtain a writable file descriptor to the host's /proc/self/exe target and overwrite the on-disk runc binary before the host process finished executing it. The next time any container was started or entered on that host — by any tenant — the poisoned binary would run with root privileges, giving the attacker full host compromise.
The result was a complete escape from container isolation: a process confined to a single container namespace could pivot to arbitrary code execution on the underlying host, defeating the primary security boundary that Docker and Kubernetes rely on for multi-tenant workloads.
Affected Versions and Components
CVE-2019-5736 affects runc versions prior to 1.0-rc6, and by extension every container platform that bundled a vulnerable runc release, including:
- Docker (Docker Engine / Docker CE and EE) prior to 18.09.2
- containerd prior to the patched 1.2.4 release
- CRI-O prior to 1.13.2
- LXC, which uses a comparable re-exec pattern and shipped its own hardening in response
- Kubernetes clusters, Apache Mesos, and Amazon ECS deployments running any of the above container engines underneath, since the vulnerability lives in the shared runtime layer rather than in the orchestrator
Exploitation required either the ability to run docker exec into an existing container with a specially crafted target, or the ability to get a victim to start a new container from an attacker-supplied image whose entrypoint exploited the re-exec race. In both cases, no host-level privileges were needed beyond what the container itself already had — this is precisely what made it a genuine container escape rather than a theoretical concern.
CVSS, EPSS, and KEV Context
NVD scored CVE-2019-5736 with a CVSS v3 base score of 7.2 (High), reflecting the low attack complexity and the severe confidentiality, integrity, and availability impact of full host root compromise, offset somewhat by the requirement for elevated privileges within the container to trigger the re-exec race. Public proof-of-concept exploit code circulated within days of disclosure, which historically correlates with elevated EPSS (Exploit Prediction Scoring System) likelihood-of-exploitation estimates for a vulnerability of this class — container escape bugs with working public exploits tend to sit well above the median EPSS percentile even years after disclosure, since scanners and red teams continue to test for unpatched runtimes. CVE-2019-5736 does not currently appear on CISA's Known Exploited Vulnerabilities (KEV) catalog, which is reserved for vulnerabilities with confirmed evidence of exploitation in the wild; the absence from KEV should not be read as low risk, given how directly it undermines container isolation on any host that never patched.
Timeline
- Discovery: Adam Iwaniuk and Borys Popławski identified the
/proc/self/exeoverwrite technique and reported it to the runc maintainers; Aleksa Sarai and Twistlock researcher Yuval Avrahami independently converged on related findings. - February 2019: The issue was assigned CVE-2019-5736 and put under a coordinated, embargoed disclosure timeline involving major cloud and container vendors (Docker, Red Hat, Google, AWS, and others).
- February 11, 2019: Details of the vulnerability began circulating publicly ahead of the planned embargo date, prompting Aleksa Sarai to post full disclosure and remediation guidance to the oss-security mailing list so that operators could patch immediately rather than remain exposed while incomplete information spread.
- Patch release: The runc project shipped a fix in the 1.0-rc6 release that closes the
/proc/self/exerace by cloning a memfd-backed copy of the runc binary at startup and executing that sealed copy instead of the on-disk file, removing the writable target entirely. Docker, containerd, CRI-O, and downstream Linux distributions shipped corresponding patched builds within days.
Remediation Steps
Because CVE-2019-5736 lives in the container runtime rather than any single application, remediation is primarily an infrastructure patching exercise:
- Upgrade runc to 1.0-rc6 or later. This is the actual fix; everything downstream depends on it.
- Upgrade Docker Engine to 18.09.2 or later, or the corresponding patched release for your distribution's packaged Docker build.
- Upgrade containerd to 1.2.4+ and CRI-O to 1.13.2+ if you run Kubernetes with either as the container runtime interface.
- Patch or rebuild base OS images and node AMIs used by managed Kubernetes services (EKS, GKE, AKS) — node images bundle their own runc, so orchestrator-level patches alone are not sufficient.
- Enable user namespace remapping for Docker where feasible; remapping the container's root UID to an unprivileged host UID removes the write access needed to overwrite the host runc binary, providing defense-in-depth even against variants of the bug.
- Enforce mandatory access control (SELinux or AppArmor) in enforcing mode. Red Hat noted that a correctly configured SELinux policy blocked exploitation attempts even on unpatched systems, because the policy denied the container process write access to the host runc binary path.
- Restrict
docker execand untrusted image execution. Treat bothdocker execinto containers you don't fully trust anddocker runof unvetted images as privileged operations, and gate them behind the same scrutiny you'd apply to host access. - Inventory your runtime versions continuously. Because the affected component sits below the application layer, teams frequently discover stale runc or containerd binaries on nodes long after the orchestrator and application images have been updated.
How Safeguard Helps
CVE-2019-5736 is a textbook example of supply chain risk hiding below the application layer — the vulnerable component isn't a library your developers imported, it's the runtime your entire container platform depends on, often several layers removed from anything a normal SCA scan inspects. Safeguard is built to close exactly that gap.
Safeguard continuously inventories the full software bill of materials across your build and runtime environments — including base images, container runtimes like runc and containerd, and the orchestration layer itself — so that a CVE like this one is flagged the moment it's published, not months later during an audit. Rather than relying on point-in-time scans of application dependencies, Safeguard correlates vulnerability intelligence (CVSS severity, EPSS exploitation likelihood, and KEV status) against your actual deployed infrastructure to tell you which nodes are still running a vulnerable runc, which clusters need a node image rebuild, and which of those hosts are exposed to untrusted or multi-tenant workloads that make exploitation realistic.
For a vulnerability class like container escape — where the difference between "patched" and "vulnerable" is a single binary version buried inside a node AMI — that kind of continuous, infrastructure-aware visibility is the difference between remediating in hours and discovering the exposure during an incident. Safeguard turns CVE-2019-5736-style runtime risk from a manual patching scavenger hunt into a tracked, verifiable control, giving security and platform teams a single source of truth for whether their container fleet is actually closed against known escape techniques.