documented case, not a live check
xz / liblzma
5.6.0 · CVE-2024-3094 · disclosed March 2024
The release tarball was generated from the attacker's branch, not from the public tag. Distros built the tarball. The git tag did not contain what the tarball contained.
shipped only m4/build-to-host.m4 (modified)
shipped only tests/files/bad-3-corrupt_lzma2.xz
shipped only tests/files/good-large_compressed.lzma
at tag same paths, different content / absent
During ./configure, the m4 macro decoded a payload from the test fixtures and patched liblzma so sshd would accept a hidden key. The repository's own history never showed the payload.
Why the lockfile can't see it: a lockfile records the artifact's version and hash. The hash of the malicious tarball is correct — it is the hash of the thing that was served. Integrity is not provenance.
documented case, not a live check
tj-actions/changed-files
tags v35–v45 · CVE-2025-30066 · disclosed March 2025
A stolen token let an attacker push a malicious commit and then re-point existing tags at it. Consumers kept asking for v45; they got different code. The version string never changed.
tag v45 → 0e58ed8 benign commit (original)
tag v45 → 0e58ed8 malicious commit (re-pointed)
effect runner memory dumped to workflow logs,
base64-encoded, on every job using it
The compromise was detected by comparing the commit a tag resolved to against the commit it used to resolve to. Nothing in the workflow file changed.
Why the lockfile can't see it: Dependabot and Renovate pin owner/action@v45 — a mutable name. A lockfile that records a tag records a pointer, and pointers can be rewritten. Only a commit SHA is content-addressed.