CVE Deep Dive

Leaky Vessels (CVE-2024-21626): runc Container Escape

Published August 10, 2026 · 9 min read

The whole point of a container is isolation: code inside should not be able to touch the host. Leaky Vessels (CVE-2024-21626), disclosed by Snyk in January 2024, broke that promise in runc— the runtime underneath Docker, containerd, and Kubernetes — by leaking a file descriptor that pointed straight at the host filesystem. This is how the escape worked, what it affected, and how to make sure you are not still running a vulnerable runtime.

Leaky Vessels CVE-2024-21626 runc container escape explained

What runc is, and why a bug in it is so serious

When you run docker run or Kubernetes schedules a pod, the high-level tools eventually hand off to runc, a small binary that does the actual work of setting up namespaces, cgroups, and mounts and then executing your process inside that sandbox. Docker, containerd, CRI-O, and most Kubernetes nodes all use it. A vulnerability in runc is therefore a vulnerability in the isolation boundary itself — the exact thing containers exist to provide.

CVE-2024-21626 is rated High (CVSS 8.6). A successful exploit is a container escape: code that was supposed to be confined to a container reads and writes the host filesystem, which on a shared node means reaching other tenants' data and, often, full node compromise.

How the escape worked

The bug was a leaked file descriptor. While starting a container, runc opened some internal file descriptors that referenced locations on the host— and one of them was not closed before the container's own process began running. Because the descriptor stayed open, it was visible inside the container through /proc/self/fd/, the kernel's per-process view of open descriptors.

That gave an attacker a handle to a host directory. By setting the container's working directory to that leaked descriptor — for example /proc/self/fd/7 — subsequent relative paths resolved against the host filesystem instead of the container's. A process could then walk up and out with something as ordinary as reading ../../../../etc/shadow on the host, or writing a payload where the host would execute it. The container never broke a wall; it was simply pointed at a door runc left open.

Two ways to trigger it

What elevated this from a lab curiosity to an industry-wide scramble was that it did not require an already-running malicious container. There were two practical triggers:

  • A crafted image build. A Dockerfile could set WORKDIR /proc/self/fd/<n>, triggering the escape during docker build. Merely building an untrusted image on a vulnerable host could compromise the build machine — a direct threat to CI runners and registry build systems.
  • A crafted exec into a running container. A docker exec with the working directory aimed at the leaked descriptor could achieve the same escape against a container an attacker had access to.

The build-time vector is the one worth dwelling on: it means an image is not just something you scan for known CVEs, it is code that runs during your build. Untrusted Dockerfiles are executable content, and this CVE was a reminder to treat them that way.

Affected versions and the fix

CVE-2024-21626 affects runc up to and including 1.1.11, and was fixed in runc 1.1.12, released on the disclosure date. The full Leaky Vessels disclosure covered four CVEs:

CVEComponentIssue
CVE-2024-21626runcLeaked file descriptor enabling a container escape (fixed in 1.1.12)
CVE-2024-23651BuildKitRace in cache-mount handling during builds
CVE-2024-23652BuildKitArbitrary file deletion during build teardown
CVE-2024-23653BuildKitPrivilege check bypass in interactive build containers

The BuildKit issues were fixed in BuildKit 0.12.5 and folded into the Docker releases published alongside the disclosure. In practice you remediate all four by updating your container platform packages — Docker Engine, containerd, and BuildKit — on every host and CI runner.

Detection: where a scanner helps and where it does not

Honesty first: runc is a host component. The most important remediation is patching the container runtime on your nodes and build machines, and that is a host configuration task, not something an image scan fixes. Confirm the runc version on each host directly:

runc --version
# runc version 1.1.12 or later is patched for CVE-2024-21626

Where an artifact scanner earns its keep is the surprisingly common case of a container runtime shipped inside an image: Docker-in-Docker builders, CI images that bundle docker and runc, and toolchain images used by pipelines. Those bundled binaries are easy to forget and go stale for months. ScanRook detects the runc binary and its version when it is present in the scanned artifact and flags it against advisory data — the same installed-state approach it uses for OS packages. Pair that with a hardened runtime configuration from our container image security checklist.

Remediation checklist

  • Patch the runtime on hosts and CI runners. Update Docker Engine, containerd, and BuildKit so runc is 1.1.12 or later everywhere containers are built or run.
  • Rescan images that bundle a container runtime. Docker-in-Docker and toolchain images carry their own runc; rebuild them on a patched base and verify the version.
  • Do not build untrusted Dockerfiles on shared hosts. Treat image builds as code execution; isolate untrusted builds and keep the build host patched.
  • Reduce blast radius with runtime hardening. Non-root containers, dropped capabilities, and seccomp profiles do not fix the runc bug, but they raise the bar for turning an escape into full node control.

The lasting lesson

Leaky Vessels was a reminder that the container boundary is only as strong as the runtime enforcing it, and that the runtime is easy to forget precisely because it works invisibly. Like regreSSHion in OpenSSH, the danger came from a component nearly everyone runs and almost no one inventories. The defense is the same discipline that catches any of these: know what is actually installed on your hosts and inside your images, understand what a CVE tells you, and keep the boring components patched as diligently as the flashy application code.

Frequently asked questions

Who found Leaky Vessels?

Snyk's security research team disclosed the set of vulnerabilities in January 2024, coordinating with the runc and Docker maintainers so patches shipped on the same day as public disclosure.

Does this affect Kubernetes?

Yes. Kubernetes nodes run containers through runc via containerd or CRI-O, so a vulnerable node was exposed. Remediation is to update the container runtime packages on every node, then confirm the runc version.

Is patching the container runtime enough?

For the runc bug itself, yes — 1.1.12 closes it. But also rebuild any image that bundles its own runtime, and apply the BuildKit and Docker updates to cover the other three Leaky Vessels CVEs.

How does ScanRook help with a runtime CVE?

ScanRook cannot patch your hosts, but it detects vulnerable runc and other runtime binaries baked into images — the Docker-in-Docker and CI builder images that often go unpatched — and flags them against multi-source advisory data.

Find stale runtimes hiding in your images

Docker-in-Docker and CI builder images bundle their own runc and containerd, and those copies go unpatched for months. ScanRook detects the binaries inside an artifact and matches them against OSV, NVD, and vendor advisory data. Upload an image to check.

Related Posts

More on this topic.