Cloud Security Office Hours Banner

XZ Utils Backdoor 2024

Step-by-step kill chain mapped to MITRE ATT&CK Cloud, sourced from official post-mortems and primary technical analyses.

2021-March 2024 Critical Open Source

XZ Utils - A Two-Year Campaign to Become the Maintainer → Backdoor Shipped Only in Release Tarballs → IFUNC Hook Into sshd → Pre-Auth RCE for One Ed448 Key

CVE-2024-3094, CVSS 10.0. Beginning in 2021, an identity using the name "Jia Tan" spent roughly two years building a contribution history in XZ Utils, a compression library present on essentially every Linux system. Suspected sock puppet accounts - names including "Jigar Kumar", "krygorin4545" and "misoeater91" - pressured the exhausted original maintainer, Lasse Collin, to hand over responsibility. In January 2023 Jia Tan had maintainer privileges. In February 2024 versions 5.6.0 and 5.6.1 shipped a backdoor that was not in the git repository: it was injected through a modified build-to-host.m4 present only in the release tarballs, and only activated on x86-64 Linux builds using glibc and GCC packaged via dpkg or rpm. Through the systemd-to-liblzma linkage it hooked RSA_public_decrypt in sshd, giving pre-authentication remote code execution to whoever held a specific Ed448 private key. It was caught by accident. Andres Freund, a Microsoft engineer investigating a performance regression, noticed sshd logins taking about half a second longer than they should.

~2 years of legitimate contributions before the payload
CVSS 10.0 - pre-auth RCE, but only for the key holder
Not in git - the backdoor existed only in release tarballs
Caught by a ~500ms latency anomaly nobody was looking for
📄 Andres Freund - Original oss-security disclosure ↗ 📄 JFrog - CVE-2024-3094 technical analysis ↗
🎭 Resource Development - Building a Reputation on Purpose
01
From August 2021 an identity using the name "Jia Tan" created accounts, joined the mailing list, and contributed legitimate patches to XZ Utils for roughly two years
T1585 - Establish Accounts T1587.001 - Develop Capabilities: Malware

Every other supply-chain chain on this page starts with theft or exploitation - a stolen token, a phished maintainer, a poisoned build step. This one starts with work. The account was created in August 2021; the contributions that followed were real, useful, and reviewed, and they continued for about two years before anything malicious appeared. That patience is the entire innovation. There is no exploit to detect and no anomaly to alert on, because for two years the attacker was doing exactly what a valuable open-source contributor does, and the community's response - trust, gratitude, increasing responsibility - was the correct response to what it could observe.

August 2021: GitHub account created
Early 2022: Joins the XZ mailing list, begins contributing minor patches
Duration: Roughly two years of legitimate, useful, reviewed contributions
Detectable anomaly during this phase: None
Why it works: The community's trust was a correct inference from everything visible
Long ConJia TanLegitimate ContributionsT1585
😤 Social Engineering - Sock Puppets Applied to a Burned-Out Volunteer
02
Accounts including "Jigar Kumar", "krygorin4545" and "misoeater91" publicly pressured maintainer Lasse Collin over slow releases, pushing him toward handing responsibility to Jia Tan
T1656 - Impersonation

The pressure campaign is the part worth reading in the original mailing-list archives, because it is genuinely difficult to look at. Multiple accounts, now believed to be sock puppets, complained about the pace of XZ releases and pushed for a new maintainer - while Collin, who maintained the project as an unpaid volunteer, had publicly mentioned mental health difficulties and limited time. The campaign exploited that directly. By January 2023 Jia Tan held maintainer privileges, and in March 2023 made the first release. This attack targeted the sustainability crisis in open source as precisely as any technical vulnerability: the exploit was one exhausted person maintaining critical infrastructure alone for free, which describes a large fraction of the dependency tree every organization on this page relies on.

Sock puppets: "Jigar Kumar", "krygorin4545", "misoeater91" and others
Method: Public complaints about release pace, pressure for a new maintainer
Target: An unpaid volunteer who had spoken publicly about limited time and mental health
January 2023: Jia Tan obtains maintainer privileges
March 2023: Jia Tan makes their first release, 5.4.2
Sock PuppetsMaintainer BurnoutPressure CampaignT1656
🧱 Preparation - Laying the Groundwork Months in Advance
03
In mid-2023, changes adding IFUNC support to crc64_fast.c went in - infrastructure the backdoor would later depend on, committed openly and reviewed as ordinary optimization work
T1195.001 - Compromise Software Dependencies and Development Tools

Around June 2023 a series of changes added indirect function (IFUNC) support to the CRC code. IFUNC is a legitimate glibc mechanism that lets a program select an optimized implementation at load time based on CPU features, and in a compression library that is exactly the kind of performance work you would expect and welcome. It also provides a hook point that runs during dynamic linking, before main, which is what the backdoor would later use. Splitting the attack this way means no single commit ever looks wrong: the enabling infrastructure arrives months early with a genuine justification, and the payload arrives later as data rather than as reviewable source. Code review catches malicious code; it does not catch a legitimate capability being added early by someone who intends to use it later.

June 2023: IFUNC support added to crc64_fast.c
What IFUNC is: A glibc mechanism selecting an optimized implementation at load time
Why it is plausible: Exactly the performance work a compression library should do
What it provides: A hook point executing during dynamic linking, before main
Why review missed it: No individual commit is malicious; the capability is genuine
IFUNCStaged PreparationPlausible CommitT1195.001
📦 Supply Chain - The Backdoor Was Never in Git
04
Versions 5.6.0 and 5.6.1 carried a modified build-to-host.m4 that existed only in the release tarballs, not in the git repository, and extracted the payload from test files during the build
T1027 - Obfuscated Files or Information T1195.002 - Compromise Software Supply Chain

This is the detail that defeats how nearly everyone verifies open-source software. Auditing the git repository would have found nothing, because the malicious build-to-host.m4 was present only in the tarballs Jia Tan released separately. The payload itself lived in files that looked like binary compression test fixtures - exactly the kind of unreadable blob a compression project legitimately contains by the hundred - and the modified build script extracted and assembled it during compilation. The injection was also conditional, running only when building on x86-64 Linux with glibc and GCC under dpkg or rpm, which narrowed it to the distribution packages that mattered while keeping it invisible almost everywhere else, including in most casual build-from-source testing.

Affected versions: XZ Utils 5.6.0 and 5.6.1
Injection point: A modified build-to-host.m4, present only in release tarballs
Payload location: Files resembling binary compression test fixtures
Conditions: x86-64 Linux, glibc, GCC, built via dpkg or rpm
Why audits missed it: The git repository was clean; the tarball was not
build-to-host.m4Tarball vs GitTest Fixture PayloadT1027
🔓 The Backdoor - Hooking sshd Through a Library It Never Uses
05
Via the systemd-to-liblzma linkage, the IFUNC resolver hooked RSA_public_decrypt in sshd, giving pre-authentication remote code execution to a client holding a specific Ed448 private key
T1574 - Hijack Execution Flow T1554 - Compromise Host Software Binary

OpenSSH does not depend on liblzma. It got there transitively: several distributions patch sshd to integrate with systemd notification, systemd links against liblzma, and so a compression library ends up inside the address space of the most security-critical daemon on the machine. The backdoor used its IFUNC hook to intercept RSA_public_decrypt during authentication, so a client presenting a certificate signed with the attacker's Ed448 key could have commands executed before authentication completed. Two properties are worth noting. The backdoor was authenticated - only the key holder could use it, so it was not a vulnerability others could stumble into and it left no obvious open door. And the reachability came from a dependency relationship nobody had deliberately created, which is the general hazard: your attack surface includes what your dependencies' dependencies are linked into.

Linkage: Distribution-patched sshd → systemd → liblzma
Hook: IFUNC resolver intercepting RSA_public_decrypt during authentication
Capability: Pre-authentication remote code execution as root
Access control: Restricted to the holder of a specific Ed448 private key
General lesson: Your attack surface includes what your transitive dependencies are linked into
RSA_public_decryptEd448Pre-Auth RCETransitive LinkageT1574
🔍 Discovery - Half a Second of Unexplained Latency
06
Andres Freund, investigating a performance regression in Debian, noticed sshd using unexpectedly high CPU and about 500ms of extra latency, profiled it, and found the time going into liblzma

There is no defensive lesson in the discovery, and pretending otherwise would be dishonest. A Microsoft engineer and PostgreSQL developer was doing unrelated performance work, noticed that SSH logins on a testing distribution felt slightly slow, and was curious enough to profile rather than shrug. That led to liblzma consuming CPU it had no business consuming, and from there to the backdoor, which he disclosed on the oss-security mailing list on March 29, 2024. Because the malicious versions had reached mainly testing and rolling distributions - Debian sid, Fedora Rawhide and 40 beta, openSUSE Tumbleweed, Kali - the blast radius on stable production systems was small. Had it survived a few more months into stable releases of major distributions, it would have been present on a very large share of the internet's Linux servers, with pre-auth root access available to one party.

Discoverer: Andres Freund, Microsoft engineer and PostgreSQL developer
Signal: ~500ms extra sshd latency and unexplained CPU usage
Method: Profiling sshd during unrelated performance work
Disclosed: March 29, 2024 on the oss-security mailing list
Reached: Mainly testing and rolling distros - Debian sid, Fedora Rawhide/40 beta, openSUSE Tumbleweed, Kali
Counterfactual: A few more months and it would have been in stable releases worldwide
Andres FreundLatency AnomalyNear MissCVE-2024-3094

🛡 How to Defend Against This Chain

Build from the repository, not from tarballs, and verify the two match. The single most transferable control here. The git tree was clean and the release tarball was not, so any verification anchored on the repository would have missed it and any process that reproduced the tarball from the tree would have caught it. Prefer builds from tagged source, use reproducible builds where you can, and check that released artifacts correspond to the commits they claim - the same class of check that would have caught LiteLLM's untagged PyPI uploads.
Reduce what is linked into your most critical processes. A compression library ended up inside sshd because of a distribution patch for systemd notification. Prefer minimal distributions and images, remove unnecessary integrations from security-critical daemons, and know the full transitive linkage of anything doing authentication. Attack surface is not what you chose to install; it is everything that ends up in the address space.
Treat maintainer sustainability as a security control, because this attack targeted it directly. The exploit was one exhausted unpaid volunteer maintaining critical infrastructure alone. Fund the projects in your dependency path, contribute maintenance effort rather than only feature requests, and support foundations doing this systematically. Every organization on this page depends on software maintained under conditions that make this attack repeatable, and money and help are the only controls that change those conditions.
Watch maintainership changes in critical dependencies as a security event. A new maintainer taking over a package deep in your tree is a supply-chain risk signal, and it is usually visible in public. Track ownership changes for the dependencies that matter most, be suspicious of pressure campaigns pushing for handover, and treat "one new maintainer, previously unknown, now has commit and release rights to something in every Linux install" as worth a look.
Take performance anomalies in security-critical paths seriously. This was found because someone did not ignore half a second. Baseline the resource profile of authentication daemons and critical services, and investigate unexplained CPU or latency changes rather than accepting them. It is a weak control and it should not have been the one that worked - but it did, and it is cheap.
Accept honestly that code review would not have caught this, and adjust expectations. Two years of legitimate contributions, an enabling change with a genuine performance justification, a payload disguised as binary test fixtures, and an injection path outside the repository entirely. No amount of reading diffs finds that. The defensible response is defence in depth around the assumption that a dependency may be hostile: minimal linkage, reproducible builds, artifact-to-source verification, and blast-radius limits on what any single compromised component can reach.

Related defense topics