The XZ Backdoor: The Maintainer Who Never Existed

The most sophisticated supply-chain attack in years wasn't caught by a scanner, an SBOM, or a security team. It was caught by one engineer annoyed that his SSH logins felt half a second slow.

In late March 2024, a Microsoft engineer named Andres Freund was doing something almost nobody does: he was bothered by half a second.

He’d been benchmarking PostgreSQL on a Debian testing machine and noticed that sshd — the OpenSSH daemon, the thing that guards remote login on most of the servers on Earth — was burning a suspicious amount of CPU. Logins felt about 500 milliseconds slower than they should. His profiler kept pointing at liblzma, the compression library from the xz-utils package, which had no business being anywhere near an SSH login. Most people would have shrugged, blamed a noisy VM, and gone back to work. Freund pulled the thread.

What he found, and posted to the oss-security mailing list on March 29, was a backdoor deliberately planted in xz-utils versions 5.6.0 and 5.6.1 — a backdoor that, on the right kind of machine, handed an attacker remote code execution on sshd before authentication. It got a CVE number, CVE-2024-3094, and the maximum possible severity score of 10.0. And the story of how it got there is more frightening than the code.

It wasn’t in the source

Here is the first thing that makes this attack special, and the thing most write-ups gloss over. If you had cloned the xz git repository and read every line, you would not have found the backdoor.

The malicious payload lived in the release tarball — the packaged .tar.gz that distributions actually download and build — but not in the version control history. The trigger was buried in a build script that autotools generates into the tarball but that nobody commits to git, and the payload itself was stashed inside the project’s test files: binary blobs labeled as corrupt-compression test cases, which is exactly the kind of file no reviewer ever opens because it’s supposed to be unreadable garbage. During a distro build, on the right architecture, those “test” files were decrypted, stitched together, and injected into the compiled library.

So the two places you’d look — the source on GitHub, and the signed release from the project’s own maintainer — disagreed with each other, and only one of them was poisoned. Every “know your dependencies” reflex we’ve built in the last five years assumes the artifact you audit is the artifact you run. This attack drove a wedge between them.

sshd doesn’t even use xz

The second clever part: OpenSSH doesn’t link against liblzma at all. Upstream sshd has nothing to do with compression libraries. So how did a compression bug become an SSH backdoor?

Through a side door that several major distributions installed themselves. Debian and Fedora patch OpenSSH to talk to systemd — so the daemon can signal “I’m ready” during boot — and that patch links sshd against libsystemd, and libsystemd pulls in liblzma as a dependency. The attacker didn’t need OpenSSH to trust xz. He needed the packaging to drag xz into the same process as sshd, and on Debian and Red Hat family systems, it did.

Once loaded, the backdoor used a GNU indirect-function (IFUNC) resolver — a legitimate mechanism for picking an optimized version of a function at load time — to hook itself into the dynamic linker and intercept the routine OpenSSH uses to verify a key. A client presenting the right payload, signed with an Ed448 key that only the attacker held, would skip authentication entirely and run commands as the server. Anyone else poking at it saw nothing: no new open port, no rogue process, just a well-behaved SSH server that happened to answer to one specific master key.

The part that should keep you up at night

The code is elegant and awful, but it’s not the scary part. The scary part is how the attacker got commit rights.

xz-utils was, for years, essentially one person: Lasse Collin, an unpaid volunteer maintaining a compression library that had quietly become load-bearing infrastructure for the entire Linux world. Around 2021, a contributor using the name “Jia Tan” (the GitHub handle JiaT75) started sending patches. They were competent. They kept coming. Jia Tan was patient, helpful, exactly the kind of contributor a burned-out solo maintainer prays for.

Then the pressure campaign started. Through 2022, a cast of accounts with names like “Jigar Kumar” and “Dennis Ens” showed up in the mailing list to complain that xz was stagnating, that Collin wasn’t merging fast enough, that the project needed a new maintainer with more time. Collin, who had been open about struggling with his own workload and mental health, pushed back — and then, worn down, started handing responsibility to the helpful newcomer who’d been so reliable. By 2023, Jia Tan was making releases. The sockpuppets who’d demanded a co-maintainer went quiet the moment they got one. They had never wanted the project fixed. They’d wanted a key.

Nobody knows who Jia Tan actually was. The commit timestamps drift around like someone editing their timezone to look plausibly Asian-Pacific; the operational discipline — years of legitimate work to establish trust before spending it once — reads like a professional, funded operation, not a lone hobbyist. The name on the commits belongs to no one. The maintainer everyone trusted never existed.

What actually saved us was luck

We got away with it. The poisoned versions were still rolling through testing and rolling-release distributions — Debian sid, Fedora Rawhide, openSUSE Tumbleweed, Kali — and had not yet reached the stable, enterprise releases where the real damage would have been done. A few more weeks and 5.6.x would have been in places that matter.

But be honest about why we got away with it. Not a scanner. Not an SBOM. Not a security team doing threat modeling. The most sophisticated open-source supply-chain attack we’ve ever documented was caught because one meticulous engineer was irritated that his benchmarks were noisy and refused to let it go. That’s not a control. That’s a lottery ticket that happened to hit.

And notice what our standard playbook would have done. A software bill of materials would have dutifully recorded that you were running xz 5.6.1 — a real version, a legitimate release, correctly signed off by the project’s own maintainer. Every provenance check would have passed, because the provenance was genuine. The attacker was the maintainer. You cannot verify your way out of trusting the wrong person; the signature is only as good as the hand that holds the key.

The uncomfortable lesson isn’t “audit your dependencies harder.” It’s that a shocking amount of the internet rests on libraries maintained by one exhausted volunteer, for free, in their spare time, and that the cheapest way to compromise that infrastructure is not to break the cryptography but to befriend the human and wait. We spent two decades hardening the code. The XZ backdoor was a reminder that the softest, least-monitored, most-load-bearing component in the whole supply chain is the maintainer — and that some adversaries are patient enough to spend two years becoming one.

Continue the conversation

← Back to Blog