Skip to content

CVE-2026-50195: Verified Reproduction

CVE-2026-50195: containerd CRI checkpoint import RCE

CVE-2026-50195 is verified against the affected target. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00248.

REPRO-2026-00248 RCE Jul 6, 2026 CVE entry .txt
Severity
CRITICAL
CVSS
9.9
Confidence
HIGH
Reproduced in
39m 23s
Tool calls
315
Spend
$10.44
01 · Overview

What Is CVE-2026-50195?

CVE-2026-50195 is a critical containerd vulnerability (CWE-345, insufficient verification of data authenticity) in the CRI checkpoint import path. Trusting attacker-supplied checkpoint metadata lets an attacker poison a node's local image cache and achieve remote code execution on the host. Pruva reproduced it (reproduction REPRO-2026-00248).

02 · Severity & CVSS

CVE-2026-50195 Severity & CVSS Score

CVE-2026-50195 is rated critical severity, with a CVSS base score of 9.9 out of 10.

CRITICAL threat level
9.9 / 10 CVSS base
Weakness CWE-345 (Insufficient Verification of Data Authenticity)

Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.

How to Reproduce CVE-2026-50195

$ pruva-verify REPRO-2026-00248
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00248/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-50195

Remote code execution — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

checkpoint archive config.dump rootfsImageRef=localhost:5000/attacker:latest and rootfsImageName=localhost:5000/victim:stable

Attack chain
  1. CRI CreateContainer checkpoint import followed by CRI CreateContainer/StartContainer for poisoned victim image tag
Runnable proof: reproduction_steps.sh
Captured evidence: vulnerable v222 exploit stdoutvulnerable v222 containerdfixed v225 exploit stdoutfixed v225 containerd
How the agent worked 674 events · 315 tool calls · 39 min
39 minDuration
315Tool calls
142Reasoning steps
674Events
Agent activity over 39 min
Support
18
Hypothesis
2
Repro
474
Judge
46
Variant
129
0:0039:23

Root Cause and Exploit Chain for CVE-2026-50195

Versions: containerd versions before the patched releases 2.3.2, 2.2.5, and 2.1.9. The runtime proof uses vulnerable v2.2.2 and fixed negative control v2.2.5.

CVE-2026-50195 is a containerd CRI checkpoint import vulnerability in which metadata inside an attacker-supplied checkpoint archive is trusted during CreateContainer. In vulnerable containerd v2.2.2, the checkpoint config.dump fields rootfsImageRef and rootfsImageName are used to pull an attacker-controlled image and then create an arbitrary local image tag for it. The reproduction proves the real CRI path by importing a malicious checkpoint archive through the containerd CRI gRPC socket, poisoning localhost:5000/victim:stable so it points to localhost:5000/attacker:latest, and then creating and starting a normal victim container from the poisoned tag. The victim container runs the attacker image command and prints PRUVA_CODE_EXEC_FROM_ATTACKER_IMAGE uid=0 gid=0 image=attacker.

  • Package/component affected: github.com/containerd/containerd/v2, specifically the CRI plugin's checkpoint import path in internal/cri/server/container_checkpoint_linux.go reached from CreateContainer.
  • Affected versions: containerd versions before the patched releases 2.3.2, 2.2.5, and 2.1.9. The runtime proof uses vulnerable v2.2.2 and fixed negative control v2.2.5.
  • Risk level and consequences: Critical. An attacker who can submit a crafted CRI checkpoint image/archive can poison a node's local image cache by forcing an arbitrary local tag to resolve to attacker-controlled image content. A subsequent pod/container using that local tag with an already-present/no-pull workflow can execute attacker-controlled code under the victim container identity.

Impact Parity

  • Disclosed/claimed maximum impact: Code execution via CRI checkpoint import API by causing the host to pull and run an attacker image.
  • Reproduced impact from this run: Code execution. The vulnerable run used the real CRI endpoint to import the crafted checkpoint, created the poisoned victim:stable tag, then successfully invoked StartContainer for a normal victim container. The victim container executed the attacker image command and produced the marker PRUVA_CODE_EXEC_FROM_ATTACKER_IMAGE uid=0 gid=0 image=attacker.
  • Parity: full.
  • Not demonstrated: The proof runs in an isolated privileged Docker runner rather than a full Kubernetes cluster/kubelet. It nevertheless exercises the production containerd CRI gRPC service and CRI container lifecycle (runp, create, start) with official containerd release binaries.

Root Cause

The vulnerable checkpoint import implementation reads untrusted checkpoint metadata from config.dump and uses it as authoritative image identity. In v2.2.2, CRImportCheckpoint does the following:

  1. Reads config.RootfsImageRef from the checkpoint metadata.
  2. Calls c.client.GetImage(ctx, config.RootfsImageRef) and, if missing, c.client.Pull(ctx, config.RootfsImageRef), which pulls the attacker-selected image reference.
  3. Parses config.RootfsImageName as a valid tag.
  4. Reads the pulled image service record for config.RootfsImageRef, rewrites tagImage.Name = config.RootfsImageName, and calls c.client.ImageService().Create(ctx, tagImage).

That final tag creation step lets the checkpoint archive bind attacker image content to an arbitrary local tag. The fixed v2.2.5 code removes the vulnerable retagging block; in the negative control, the attacker image is still pulled for the checkpoint restore path, but the arbitrary victim:stable local tag is not created, so the later victim CreateContainer fails with not found instead of running attacker code.

The script records source evidence in bundle/logs/source/patch_check.txt, including the vulnerable v2.2.2 tag creation block and the fixed v2.2.5 corresponding block where it is absent.

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh from the bundle root (the script is self-contained and uses PRUVA_ROOT if set).
  2. The script:
    • Starts a local Docker registry and builds/pushes three images: pause, a legitimate victim:stable, and an attacker image whose CMD prints PRUVA_CODE_EXEC_FROM_ATTACKER_IMAGE.
    • Downloads official containerd v2.2.2 and v2.2.5 release binaries, plus runc and crictl.
    • Builds two privileged runner containers that run real containerd CRI services.
    • For v2.2.2, creates a pod sandbox, imports a malicious checkpoint archive through crictl create where rootfsImageRef=localhost:5000/attacker:latest and rootfsImageName=localhost:5000/victim:stable, then creates and starts a normal victim container from victim:stable.
    • For v2.2.5, repeats the same flow as a fixed negative control.
  3. Expected evidence:
    • Vulnerable run: POST-CHECKPOINT: poisoned victim tag entries = 1, StartContainer rc=0, and victim logs contain PRUVA_CODE_EXEC_FROM_ATTACKER_IMAGE uid=0 gid=0 image=attacker.
    • Fixed run: POST-CHECKPOINT: poisoned victim tag entries = 0, victim CreateContainer fails with failed to resolve image "localhost:5000/victim:stable": not found, and no attacker marker appears.

Evidence

Primary proof artifacts:

  • bundle/logs/exploit_evidence.txt — concise vulnerable/fixed verdict summary.
  • bundle/logs/vulnerable_v222_exploit_evidence.txt — full vulnerable CRI flow and code execution marker.
  • bundle/logs/fixed_v225_exploit_evidence.txt — fixed negative control.
  • bundle/logs/vulnerable_v222_containerd.log and bundle/logs/fixed_v225_containerd.log — containerd service logs.
  • bundle/logs/vulnerable_v222_ctr_images.txt and bundle/logs/fixed_v225_ctr_images.txt — image store evidence.
  • bundle/repro/runtime_manifest.json — runtime manifest with entrypoint_kind=api_remote, service/health/target true, and artifact list.

Key excerpts from the successful vulnerable run:

containerd: containerd github.com/containerd/containerd/v2 v2.2.2 301b2dac98f15c27117da5c8af12118a041a31d9
checkpoint config.dump: {"rootfsImageRef":"localhost:5000/attacker:latest","rootfsImageName":"localhost:5000/victim:stable", ...}
POST-CHECKPOINT: attacker image entries = 1
POST-CHECKPOINT: poisoned victim tag entries = 1
localhost:5000/attacker:latest ... sha256:25ff2e0f0b209d91423507e05f4a369614a1014f46b6bceea502fd24fe7d289f
localhost:5000/victim:stable   ... sha256:25ff2e0f0b209d91423507e05f4a369614a1014f46b6bceea502fd24fe7d289f
StartContainer rc=0
PRUVA_CODE_EXEC_FROM_ATTACKER_IMAGE uid=0 gid=0 image=attacker
VERDICT: VULN_CODE_EXEC_CONFIRMED

Key excerpts from the fixed negative control:

containerd: containerd github.com/containerd/containerd/v2 v2.2.5 e53c7c1516c3b2bff98eb76f1f4117477e6f4e66
POST-CHECKPOINT: attacker image entries = 1
POST-CHECKPOINT: poisoned victim tag entries = 0
creating container: rpc error: code = NotFound desc = failed to check if this is a checkpoint image: failed to resolve image "localhost:5000/victim:stable": not found
VERDICT: FIXED_BLOCKED - fixed containerd did not create the victim tag and no attacker code executed

Environment details captured:

  • Official containerd v2.2.2 and v2.2.5 Linux amd64 release binaries are downloaded by the script.
  • crictl drives the real CRI gRPC endpoint at /run/containerd/containerd.sock inside the privileged runner.
  • The runtime manifest confirms service_started=true, healthcheck_passed=true, and target_path_reached=true.

Recommendations / Next Steps

  • Upgrade containerd to one of the patched versions: 2.3.2 or later, 2.2.5 or later on the 2.2 branch, or 2.1.9 or later on the 2.1 branch.
  • Preserve the fixed behavior that prevents checkpoint metadata from creating arbitrary local image tags for pulled base images.
  • Add regression tests around CRI checkpoint import where rootfsImageRef and rootfsImageName intentionally differ. The expected result should be that checkpoint import does not create or overwrite the arbitrary local tag, and a later normal container using that tag cannot resolve to attacker content.
  • Consider additional validation of checkpoint metadata provenance and consistency between image name/reference fields before any pull or restore action.

Additional Notes

  • The final bundle/repro/reproduction_steps.sh was executed successfully twice consecutively in this run.
  • The proof uses an isolated Docker network and local registry, so it is repeatable and does not depend on an external attacker registry after initial base-image/tool downloads.
  • The fixed v2.2.5 negative control still pulls the attacker base image for checkpoint restore, but it no longer creates the arbitrary victim tag. This distinction matches the reproduced exploit chain and is why the subsequent victim CreateContainer/StartContainer cannot execute attacker code on the fixed build.

CVE-2026-50195 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:000:56
0:00
session startedaccounts/fireworks/routers/glm-5p2-fast · CVE-2026-50195 · REPRO-20
0:02
0:04
web search
0:05
web search
0:08
0:09
0:11
web search
0:14
0:15
web search
0:17
web search
0:26
0:27
extract_facts
no facts extracted
0:28
0:28
0:28
supportrepro
0:42
0:44
0:44
0:44
0:45
0:46
0:46
0:48
0:48
0:52
0:52
$cd /data/pruva/project-cache/9e790cda-4e27-4fc2-9ed7-a2678dd1691a/repo && git log --oneline -20 && echo "---VERSION---" && cat version/version.go && echo "---STATUS---" && git status && echo "---DESCRIBE---" && git describe --tags 2>/dev/null || echo "no tags describe"
0.2s
{"cwd":"/data/pruva/runs/baed833a-b876-4531-9a22-8e8362fc5e5b","duration_ms":208,"exit_code":0,"stderr":"","stdout":"301b2dac9 Merge pull request #12998 from samuelkarp/prepare-release-2.2.2\n7e6ecf434 Prepare release notes for v2.2.2\n5dc7bb27e Merge pull request #12987 from k8s-infra-cherrypick-robot/cherry-pick-12617-to-release/2.2\na20dead7c set default config_path in plugin init\n8b085dd5d Merge pull request #12936 from fidencio/release-2.2/backport-12835\n7022bea84 Merge pull request #12957 from k8s-infra-cherrypick-robot/cherry-pick-12950-to-release/2.2\n68855cb0b ci: modprobe xt_comment on almalinux\n46fabcc77 Merge pull request #12944 from k8s-infra-cherrypick-robot/cherry-pick-12941-to-release/2.2\nef7a8beb3 core/mount: add test for getUnprivilegedMountFlags\n07b2cc07e core/mount: fix getUnprivilegedMountFlags iterating over indices instead of values\na5f83d8c2 cri: unpack images with per-layer labels for runtime-specific snapshotters\n842cbd07e Merge pull request #12926 from k8s-infra-cherrypick-robot/cherry-pick-12923-to-release/2.2\n54101116f add integration test for cni result nil\nd44c4384e address comment\nf1835270b fix issue where cni del is never executed\n3661d86… [truncated]
0:56
08 · How to Fix

How to Fix CVE-2026-50195

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-50195 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-50195

How does the CVE-2026-50195 attack work?

An attacker imports a malicious checkpoint archive through the containerd CRI gRPC socket, poisoning a local tag such as localhost:5000/victim:stable to resolve to an attacker-controlled image (e.g. localhost:5000/attacker:latest). A subsequent normal container creation using that poisoned tag runs the attacker's image command instead of the legitimate one, printing evidence of code execution as root.

Which containerd versions are affected by CVE-2026-50195, and where is it fixed?

Containerd versions before 2.3.2, 2.2.5, and 2.1.9 are affected. The reproduction confirms v2.2.2 is vulnerable and v2.2.5 is a fixed negative control.

How severe is CVE-2026-50195?

Critical. An attacker who can submit a crafted CRI checkpoint archive can poison a node's local image cache and cause subsequent containers using the poisoned tag to execute attacker-controlled code, potentially as root.

How can I reproduce CVE-2026-50195?

Download the verified script from this page and run it in an isolated environment against containerd v2.2.2. It imports a malicious checkpoint archive via the CRI gRPC socket to poison a local image tag, then creates and starts a normal container from that tag and confirms the attacker image's command executes as root; confirm v2.2.5 blocks the poisoning.
11 · References

References for CVE-2026-50195

Authoritative sources for CVE-2026-50195 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.