XZ Utils Backdoor
A three-year social-engineering operation to backdoor sshd on every Linux distro
No public attribution has been made by any government agency. The sophistication of the social engineering, the patience of the multi-year operation, and the surgical precision of the technical payload are widely assessed as indicative of a well-resourced state actor. The identity behind the 'Jia Tan' persona remains unknown.
An unknown actor operating as 'Jia Tan' (GitHub: JiaT75) spent roughly two years cultivating trust in the xz-utils open-source project before inserting a cryptographically authenticated backdoor into the release tarballs of versions 5.6.0 and 5.6.1. Disguised as test fixture files, the payload was extracted at build time by a malicious Bash script in m4/build-to-host.m4, which injected a rogue object file into liblzma. Because Debian and RPM-family distributions patch OpenSSH to link libsystemd — which in turn links liblzma — every sshd process on affected rolling/testing distributions loaded the compromised library. The backdoor used IFUNC resolver hooking to intercept OpenSSL's RSA_public_decrypt function, enabling the attacker to authenticate to any targeted host using a private Ed448 key never made public. The attack was discovered by Andres Freund on March 28–29, 2024, while investigating anomalous SSH latency during unrelated PostgreSQL benchmarking.
- Phase 03 · Privilege Escalation — Co-Maintainer AccessTA0004
Jia Tan gains commit rights and full co-maintainer status over 14 months of patience
- October 28, 2022: Jia Tan was added to the Tukaani GitHub organization, granting them triage and review permissions.
- December 30, 2022: Jia Tan received direct commit access to the xz repository — a critical escalation enabling future code injection.
- January 11, 2023: Lasse Collin released what would become his final version (v5.4.1), effectively ceding day-to-day control.
- March 18, 2023: Jia Tan cut the first release under their own authority (v5.4.2), establishing operational control over the official release pipeline.
- June 2023: Jia Tan submitted code introducing GNU indirect function (IFUNC) support — a prerequisite for the backdoor's runtime hooking mechanism — and simultaneously disabled IFUNC fuzzing in oss-fuzz on July 7, 2023, citing 'incompatibility with address sanitizer,' preventing automated detection of the future payload.
- Phase 04 · Defense Evasion — Obfuscated Test-Fixture PayloadTA0005
Malicious binary data lands in the repository disguised as benign test fixture files
- The backdoor payload was split across two files that appeared to be ordinary compressed test data: tests/files/bad-3-corrupt_lzma2.xz and tests/files/good-large_compressed.lzma — both committed to the repository by Jia Tan in February 2024.
- The files existed only in the release tarballs distributed via tukaani.org, not in the GitHub source tree — meaning standard source-code audits of the git repository would not reveal them.
- bad-3-corrupt_lzma2.xz contained Stage 1 bash code obscured by a character-translation map (tab↔space, hyphen↔underscore); applying the inverse transform with tr restored a valid xz stream.
- good-large_compressed.lzma contained the Stage 2 binary payload: a pre-compiled object file (liblzma_la-crc64-fast.o) encrypted with an AWK-implemented RC4 variant (using modular addition rather than XOR), extracted by carving alternating 1024-byte and 2048-byte blocks.
- Jia Tan disabled oss-fuzz IFUNC coverage on July 7, 2023 to prevent the fuzzer from exercising the code paths the backdoor would later hook.
Techniques - Phase 05 · Execution — Build-Time Payload InjectionTA0002
m4/build-to-host.m4 silently unpacks the payload and links the rogue object into liblzma during package build
- The malicious logic lived in m4/build-to-host.m4, a GNU autotools macro file included during the configure phase — a standard part of every source build, executed with the developer's or packager's privileges.
- Stage 0 used tr to 'uncorrupt' bad-3-corrupt_lzma2.xz, revealing a Stage 1 bash script. Stage 1 carved encrypted binary chunks from good-large_compressed.lzma using alternating head invocations, then applied a substitution cipher before final decompression.
- Stage 2 decrypted the pre-compiled object file liblzma_la-crc64-fast.o using an AWK-based RC4 variant and injected it into the build system's object list, causing it to be linked directly into the finished liblzma.so.
- The injection only activated on x86-64 Linux builds using GCC and the GNU linker when the package was being built in a Debian or RPM environment — narrowing the blast radius to exactly the distributions the attacker wanted to compromise.
- xz 5.6.0 shipped on 2024-02-24. A refinement (fixing a Valgrind-detectable anomaly) shipped as 5.6.1 on 2024-03-09.
Techniques - Phase 06 · Persistence — IFUNC Hook in sshd via libsystemd → liblzmaTA0003
The rogue liblzma loads inside every sshd process on affected distros through the libsystemd dependency chain
- Debian and RPM-family distributions patch OpenSSH to use systemd socket activation, causing the openssh-server package to link libsystemd. libsystemd in turn links liblzma — loading the compromised library into every sshd process at startup.
- Arch Linux, Gentoo, NixOS, and other distributions that do not apply the systemd-notify OpenSSH patch do not link libsystemd from sshd, and are therefore not exploitable via this vector even with the backdoored xz installed.
- The injected object file registered a GNU IFUNC resolver that replaced the legitimate implementation of a crc64 function, then at runtime redirected OpenSSL's RSA_public_decrypt to the attacker's hook code — surviving across normal process lifetime with no additional dropper.
- Because the hook lived in a shared library loaded at process start, there was no process injection, no unusual child process, and no network callback to a C2 — making the implant exceptionally clean and difficult to detect with conventional EDR telemetry.
Techniques - Phase 07 · Credential Access / Command Execution — RSA Hook RCETA0006
The attacker authenticates with a private Ed448 key and executes arbitrary commands inside the sshd process
- The IFUNC hook intercepted OpenSSL's RSA_public_decrypt function, giving the backdoor visibility into every incoming SSH public-key authentication attempt before OpenSSH's own verification logic ran.
- For each connection the hook inspected the RSA public-key modulus (the 'N' value) supplied by the connecting client. The first 16 bytes of N were used to derive a command number (0–3), selecting operations including: authentication bypass, remote command execution, and UID/GID-specified command execution.
- The backdoor decrypted the final 240 bytes of the modulus with ChaCha20 using a hardcoded key embedded in the payload, then validated a signature using an Ed448 elliptic-curve public key — ensuring only the operator possessing the corresponding private key could issue valid commands.
- Invalid payloads (normal SSH connections) fell through transparently to OpenSSH's standard authentication path, producing no detectable error and making targeted exploitation nearly invisible in logs.
- The full set of attacker capabilities was never exercised in the wild — the backdoor was caught before large-scale exploitation began.
TechniquesIndicators - Phase 08 · Discovery — Caught by Accident, Not DesignTA0007
Andres Freund notices ~500 ms SSH slowness and Valgrind errors during unrelated PostgreSQL benchmarking
- On March 28, 2024 Andres Freund (Microsoft, PostgreSQL core team) was benchmarking PostgreSQL on a Debian sid machine when he noticed SSH logins consuming anomalous CPU and taking 500–800 ms longer than expected.
- Running Valgrind on sshd revealed unexpected memory access errors originating inside liblzma — a library that should have had no involvement in SSH authentication.
- Freund traced the anomaly through the libsystemd dependency to the xz-utils package, found that the release tarball differed from the GitHub source tree in the m4/build-to-host.m4 file, and reverse-engineered the injection chain.
- He privately disclosed his findings to distributors and the oss-security mailing list on March 29, 2024. Affected distributions (Debian sid/testing, Fedora 40/41 beta, openSUSE Tumbleweed, Kali rolling) issued emergency downgrades within hours.
- The discovery was serendipitous — no automated security tooling, fuzzer, or CI pipeline caught the backdoor. The attacker had carefully disabled the one fuzzer (oss-fuzz IFUNC coverage) most likely to trigger the relevant code path.
Caltagirone / Pendergast / Betz 2013 — four-vertex attribution framework.
- Jia Tan persona (unattributed; likely state-sponsored)
- T1195.002
- T1585.001
- T1566.004
- T1078
- T1027
- +1 more
- See narrative above
- backdoor in upstream xz/liblzma leading to ssh server compromise · Andres Freund / oss-security · 2024-03-29
- Timeline of the xz open source attack · Russ Cox (swtch.com) · 2024-04-01
- CVE-2024-3094 — NVD · NIST NVD · 2024-03-29
- XZ Backdoor Attack (CVE-2024-3094) — All You Need to Know · JFrog Security Research · 2024-03-29
- xz/liblzma: Bash-stage Obfuscation Explained · Gynvael Coldwind · 2024-04-01
- XZ Utils backdoor — everything you need to know · Sam James (thesamesam) · 2024-03-30
- XZ Utils release history and backdoor statement · Tukaani Project
- T1195.002 — Supply Chain Compromise: Software Supply Chain · MITRE ATT&CK
- T1556 — Modify Authentication Process · MITRE ATT&CK
- T1574 — Hijack Execution Flow · MITRE ATT&CK