Safeguard
Cloud Security

Container runtime security (containerd/CRI-O) vulnerability roundup

Container runtime CVEs like the runc Leaky Vessels flaw and CRI-O's cr8escape show how containerd and CRI-O bugs turn into full host takeovers.

Michael
Cloud Security Architect
7 min read

Container runtimes are the layer that actually does the work Kubernetes and Docker take credit for: creating namespaces, wiring up cgroups, mounting overlay filesystems, and handing a process off to the kernel as an isolated "container." When that layer has a bug, the sandbox itself fails, and a compromised container can walk straight onto the host. Over the past five years, containerd and CRI-O — the two dominant CRI runtimes — have shipped fixes for a specific, countable set of high-severity CVEs, several with public CVSS scores above 8.0. This roundup covers the ones that matter: CVE-2024-21626 ("Leaky Vessels") in runc, CVE-2022-0811 ("cr8escape") in CRI-O, CVE-2020-15257 in containerd-shim, and the CVE-2023-25153/CVE-2023-25173 image-unpacking pair in containerd, plus what changed in each fix and how to tell if you're still exposed.

What Is Container Runtime Security and Why Does It Differ From Image Scanning?

Container runtime security protects the software that creates and isolates running containers — containerd, CRI-O, and the runc/crun binaries they shim out to — as opposed to the images those containers are built from. Image scanning (the Snyk/Trivy model) answers "does this image contain a package with a known CVE," which is a supply-chain question about artifacts at rest. Runtime security answers a different question: "can a process inside a container break its isolation boundary and touch the host kernel, host filesystem, or other containers on the same node." The distinction matters because a fully patched, zero-CVE application image running on a vulnerable containerd or CRI-O version is still one crafted image away from a host compromise. Every runtime CVE in this post is exploitable regardless of what's inside the container — the vulnerability lives in the orchestration layer, not the application.

How Did CVE-2024-21626 Let a Malicious Image Escape Its Container?

CVE-2024-21626 let a specially crafted container image or Dockerfile give a process a working directory file descriptor that pointed at the host filesystem instead of the container's rootfs, because runc's internal WORKDIR handling briefly leaked an open fd (/proc/self/fd/N) during container startup. Disclosed on January 31, 2024 by Snyk researcher Rory McNamara as part of a four-CVE set dubbed "Leaky Vessels" (CVE-2024-21626, CVE-2024-23651, CVE-2024-23652, CVE-2024-23653), it carried a CVSS score of 8.6 and affected runc versions up to and including 1.1.11. Because containerd, CRI-O, Docker Engine, and BuildKit all shim out to runc for the actual namespace/cgroup work, the blast radius covered nearly every mainstream container platform simultaneously — this wasn't a containerd-specific or CRI-O-specific bug, it was a shared foundation-layer bug. The fix landed in runc 1.1.12, and Kubernetes distributions shipped matching containerd (1.6.28, 1.7.13) and CRI-O point releases within days. If your nodes are running runc older than 1.1.12, a malicious base image can still get a host-writable file descriptor before you ever schedule a workload from it.

What Made CVE-2022-0811 ("cr8escape") a Full Node Takeover in CRI-O?

CVE-2022-0811 let an attacker with permission to deploy a pod set arbitrary kernel parameters on the node by abusing CRI-O's handling of the kernel.core_pattern sysctl, which CRI-O passed through without adequately restricting namespaced sysctls. By setting kernel.core_pattern to a pipe that executed an attacker-controlled binary whenever any process on the host crashed, an attacker could trigger arbitrary code execution outside the container as root on the node. CrowdStrike researcher Sam Nichols disclosed the bug on March 14, 2022, naming it "cr8escape"; it scored 8.8 on CVSS and affected CRI-O 1.19 through 1.22 (fixed in 1.19.6, 1.20.7, 1.21.6, and 1.22.3). The practical severity here came from the low bar to trigger it: no privileged container, no host mount, and no special SCC/PSP bypass — just the ability to run a pod and cause any process on the node to segfault, which an attacker can force deliberately. Clusters running CRI-O without those point-release patches, common in older OpenShift and Rancher deployments, remain exploitable today.

Why Was containerd-shim's Abstract Socket (CVE-2020-15257) a Host Network Escape?

CVE-2020-15257 let a process inside a container that shared the host's network namespace connect to containerd-shim's API over an abstract Unix socket and issue commands as if it were the host's containerd daemon, because abstract sockets in Linux aren't confined by filesystem or network namespaces the way regular sockets are. Disclosed in December 2020 with a CVSS score of 5.2, it affected containerd versions before 1.3.9 and 1.4.3. The catch that made it worse than the "medium" score suggested: any container running with hostNetwork: true — a setting used routinely by CNI plugins, monitoring daemonsets, and ingress controllers — had a direct path to the shim's control API and, from there, to spawning arbitrary processes on the host. The fix moved the shim to bind sockets scoped by network namespace rather than relying on the abstract socket's global Linux namespace, shipped in containerd 1.3.9 and 1.4.3. Teams that audited "which pods run as privileged" but not "which pods use hostNetwork" had a live gap here for months after disclosure.

How Did CVE-2023-25153 and CVE-2023-25173 Turn Image Extraction Into Host File Overwrites?

CVE-2023-25153 let a malicious image overwrite arbitrary files on the host during extraction by abusing hard links and symlinks in the image layer tarball, because containerd's unpack logic didn't fully validate that extracted paths stayed inside the intended rootfs directory. Disclosed in February 2023 with a CVSS score of 8.1, it affected containerd before 1.6.18 and 1.5.18. Its companion, CVE-2023-25173, scored 6.0 and stemmed from containerd not resetting supplementary group IDs when applying a container's UID/GID mapping, which under specific configurations let a container process retain host-side group permissions it shouldn't have had — for example, read access to files owned by a GID the image author never should have been granted. Both were patched in the same two releases (1.6.18 / 1.5.18), which is the practical reason security teams tracking containerd should treat "1.6.18+" as the actual floor for pulling untrusted images, not just the latest CVE-free tag.

How Should Security Teams Prioritize Runtime CVEs Instead of Patching on CVSS Score Alone?

Security teams should prioritize containerd/CRI-O CVEs by whether the affected code path is actually reachable in their cluster's configuration, not by CVSS score alone, because a 5.2-scored bug like CVE-2020-15257 was more urgent for hostNetwork-heavy clusters than several 8-point CVEs that require an attacker to already control image content. In practice that means checking three things for every runtime CVE: the exact runc/containerd/CRI-O version installed on each node (containerd --version, crio --version, or the version field in kubectl get nodes -o wide), whether the vulnerable feature is in use (hostNetwork pods, unrestricted image pull sources, sysctl allowlists), and whether the fix is a binary upgrade or requires a config change on top of it, since several of these CVEs (notably cr8escape) needed both. A cluster running containerd 1.6.12 with open image pull policies and several hostNetwork daemonsets is carrying real exposure to at least three of the five CVEs above simultaneously — that's the kind of compounding risk a version-number-only inventory misses.

How Safeguard Helps

Safeguard's reachability analysis maps whether a vulnerable runc, containerd, or CRI-O code path is actually invoked given your node configuration — hostNetwork usage, sysctl policies, image pull sources — instead of flagging every CVE-affected version as equally urgent. Griffin AI correlates that runtime exposure against your live workload graph to tell you which nodes and namespaces face real risk from CVE-2024-21626-class breakout bugs versus which are technically vulnerable but practically inert. Safeguard generates and ingests SBOMs at the node and cluster level so runtime binaries — not just application dependencies — are tracked and matched against new CVE disclosures automatically. When a fix is available, Safeguard opens auto-fix PRs that bump pinned containerd, CRI-O, or runc versions in your infrastructure-as-code, cutting the gap between disclosure and patched fleet from weeks to hours.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.