Xz, two years on: what scanners still cannot catch

gagancm2 pts0 comments

xz, two years on: what scanners still cannot catch · Arcis Blog

CVE-2024-3094 was not caught by a CVE scanner. It was caught by an engineer noticing a 500ms slowdown on SSH login. Two years later, the way we think about supply chain risk has changed. Most tooling has not caught up.

The takeaways.

The xz-utils backdoor was a maintainer-trust hijack, not a code vulnerability. CVE-driven scanners cannot catch attacks until a CVE exists.

Real-time feeds (OSV), postinstall-script scrutiny, and maintainer-shift signals close gaps that lockfile scanning structurally cannot.

Supply chain security is a maintenance discipline, not a CI-time scan. The lockfile is fresh once a quarter. The threat landscape is fresh every day.

Three practical moves: pin direct dependencies, review every lockfile diff, subscribe to a real-time feed for the languages you ship in.

The xz-utils story is the most-told supply chain story of the decade for a reason. It is the cleanest single example of a class of attacks that the security industry had been warning about for years and that almost no scanner was equipped to catch.

The short version is this. In late March 2024, Andres Freund, a PostgreSQL maintainer working at Microsoft, noticed that SSH connections to his test machine were taking around 500 milliseconds longer than usual. He could have ignored it. Most people would have. Instead he pulled on the thread, and the thread led to a backdoor that had been inserted into upstream xz-utils, a compression library that almost every Linux system depends on, by a maintainer who had been steadily building trust in the project for two years. His original message to oss-security on March 29, 2024 is the artifact every supply chain practitioner should read in full at least once.

If the backdoor had shipped to stable distros without that catch, it would have given the attacker remote code execution as root on a large fraction of the internet. Distro release schedules and a lucky observation are the only reasons it did not.

Why your scanner did not catch it

Most supply chain scanners do one thing well. They cross-reference the package versions in your lockfile against a database of known CVEs. If xz-utils 5.6.0 is in your lockfile and CVE-2024-3094 says xz-utils 5.6.0 is bad, the scanner alerts. Useful. But the alert came after a CVE existed, and a CVE existed only because Andres noticed the 500ms.

If you had run any CVE scanner against xz-utils 5.6.0 on March 28, 2024, the day before Andres posted his findings, it would have come back clean. The package had no known vulnerabilities. The maintainer had a clean reputation. The release notes were boring and routine. By every signal a static scanner could read, xz-utils 5.6.0 was a fine version to depend on.

This is the core problem. CVE-driven scanning answers "is this version known to be bad." It does not answer "is this version safe." For most of computing history these questions had the same answer. They are starting to diverge.

The trust hijack pattern

The xz attack followed a pattern that researchers had been describing in the abstract for a long time. A new contributor, identifying themselves as Jia Tan, appeared on the xz-utils project in 2021. They submitted reasonable patches. They were responsive on the issue tracker. They were helpful. Over about two years, the existing maintainer, working alone, burned out, and Jia Tan was added as a co-maintainer with commit rights.

Then the backdoor went in. Not in the source. In the build system. Specifically in the autotools m4 macros that generated the release tarballs. The git source looked clean. Anyone reviewing the repo on GitHub saw nothing wrong. The release tarball, which is what distros actually built from, contained a step that swapped in a malicious object file at link time. The detection path through a normal code review would have missed it. You would have had to compare the tarball against the git tree, byte by byte, to see the divergence.

This is the part that should keep security teams awake. The attack did not rely on a code vulnerability. It relied on the maintainer trust model. The maintainer was a real account, with a real commit history, with real pull requests merged into real downstream projects. There was no CVE to scan for because there was no flaw, in the usual sense. The package was doing exactly what its maintainer wanted it to do. The maintainer was a hostile actor.

What scanners should have caught

The honest answer is that no static lockfile scanner could have caught xz pre-disclosure. The disclosure created the CVE. The CVE updated the database. The scanners that checked the database then started alerting. That is the lag, and it is unavoidable for purely CVE-driven tools.

What modern supply chain tools are starting to add is a layer that does not depend on CVE creation. Three categories of signal show up here.

Real-time vulnerability feeds. The OSV project, run by Google, aggregates vulnerability...

maintainer utils scanner real years scanners

Related Articles