CVE
CRI-O · critical · rated critical by CRI-O; no CVSS vector publishedUpdated September 29, 2026

CVE-2026-15801: CRI-O checkpoint restore writes files as root to a path the archive chooses

How a crafted CRI-O checkpoint archive makes CRI-O write attacker-controlled content as root, which versions are affected and fixed, the configuration that closes it, and what the Kubernetes API can and cannot show.

Short answer

CVE-2026-15801 lets someone who can push an image to a registry a node pulls from and create pods make CRI-O write attacker-controlled content as root to a path of their choosing, through the io.kubernetes.cri-o.LogPath annotation of a crafted checkpoint archive; it affects CRI-O 1.37.0, 1.36.5, 1.35.8, 1.34.13 and earlier, and is fixed in 1.37.1, 1.36.6, 1.35.9 and 1.34.14.

01

What the vulnerability does

CRI-O can create a container by restoring it from a checkpoint archive. On affected versions, CRI-O takes the io.kubernetes.cri-o.LogPath annotation from that archive and writes to the path it names, as root, with content the archive's author controls.

The CRI-O advisory says this enables remote code execution and full node compromise. It needs two things: the ability to push an image to a registry the node pulls from, and the ability to create pods on the cluster.

The fix derives LogPath and the other annotations from the kubelet's CRI request instead of the untrusted checkpoint archive.

02

Affected and fixed versions

From the CRI-O advisory.

  • Affected: <=1.37.0, <=1.36.5, <=1.35.8, <=1.34.13.
  • Fixed: 1.37.1, 1.36.6, 1.35.9 and 1.34.14.
  • The advisory lists no fixed version for release lines older than 1.34.
  • The advisory says newer versions default container_level_enabled to "checkpoint_only", which blocks the vulnerable restore path. It does not say which versions changed the default, so check the value on each node rather than relying on it.

03

Check your nodes

Read the runtime version from the Kubernetes API, then check on each node whether CRI-O allows restore. container_level_enabled set to "checkpoint_restore" leaves the vulnerable path open; "checkpoint_only", the default in current CRI-O documentation, and "none" do not.

On older versions without container_level_enabled, the setting to look for is enable_criu_support. CRI-O documents it as defaulting to true, and the advisory's workaround for those versions is to set it to false.

ShellRuntime version per node, then the checkpoint settings
kubectl get nodes -o custom-columns=\
NODE:.metadata.name,\
RUNTIME:.status.nodeInfo.containerRuntimeVersion

# On the node:
crio config 2>/dev/null | grep -E \
  'container_level_enabled|enable_criu_support'

# Registries your workloads pull from:
kubectl get pods -A -o jsonpath=\
'{range .items[*]}{range .spec.containers[*]}\
{.image}{"\n"}{end}{end}' | sort -u
Exposed if the version is affected and container_level_enabled is "checkpoint_restore", or, on versions without that option, enable_criu_support is not false.

04

What Kubernetes can show, and what it cannot

The Kubernetes API shows each node's CRI-O version and the image reference each pod uses. It does not show the setting that decides exposure: container_level_enabled and enable_criu_support live in CRI-O's configuration on the node, not in any Kubernetes object. Nor does a pod spec show that its image is a checkpoint archive, or which LogPath annotation that archive carries.

So the reliable check is the CRI-O version plus the node configuration above, and the registry list tells you where a crafted archive could come from.

On the node, the write is made by the CRI-O process itself, so it does not appear as a new process. Process activity can still show the restore: CRI-O's checkpoint and restore support is CRIU integration and needs the criu binary on the node, so a criu run nobody planned is a sign a restore happened. Any code the written file later causes to run appears as process executions on the node.

05

Fixing it

Upgrade CRI-O to 1.37.1, 1.36.6, 1.35.9 or 1.34.14, and do not set container_level_enabled = "checkpoint_restore" in the [crio.checkpoint_restore] table.

The advisory's workarounds for nodes that cannot be upgraded yet: keep container_level_enabled at "checkpoint_only" (or "none"), or on older versions set enable_criu_support = false. Also restrict which registries the node can pull from and who can push to them.

The upgrade does not undo a write that already happened. The advisory describes the result as full node compromise, so treat a node where an unexpected restore ran as compromised.

06

Where Primod fits

Primod's per-node eBPF sensor records process executions and lineage per workload, so an unplanned criu restore and the processes that follow it are visible on the node where they ran. That is evidence of what happened; the configuration change and the upgrade are the fix.

Frequently asked questions

Is a default CRI-O configuration exposed?
The advisory says the default container_level_enabled = "checkpoint_only" is safe. Nodes are exposed when restore is turned on with "checkpoint_restore", or on older versions without that option when enable_criu_support is left enabled; CRI-O documents it as defaulting to true.
I already upgraded for CVE-2026-92574. Am I covered?
Not on the 1.37 line. 1.36.6, 1.35.9 and 1.34.14 are the fixed versions in both advisories, but this advisory lists 1.37.0 as affected and 1.37.1 as the fix. The configuration workaround is the same: keep restore off.
Can an admission policy catch the crafted archive?
Not by reading the pod spec: it shows an image reference, not the annotations inside a checkpoint archive. What admission policy can do is limit which registries pods pull from, which matches the advisory's second workaround.
Does someone need access to the cluster to exploit it?
Yes. The advisory requires both the ability to push an image to a registry the node pulls from and the ability to create pods on the cluster.

Sources and references

  1. GHSA-399r-2whw-f7gg: Arbitrary file write as root via checkpoint restore

    CRI-O, September 2026

  2. crio.conf(5): enable_criu_support and the crio.checkpoint_restore table

    CRI-O

  3. crio(8): the config subcommand

    CRI-O

  4. CRI-O configuration source: enable_criu_support and container_level_enabled

    CRI-O

  5. GHSA-pgj4-7h26-2r47: CRI-O checkpoint destination security-context bypass

    CRI-O

Keep reading

From the engineering blog

All articles