Safeguard
Supply Chain•

Why sshd loaded liblzma: the xz backdoor's indirect path

OpenSSH does not use xz directly. How a distribution patch and libsystemd pulled liblzma into sshd, and what that says about transitive dependencies.

Safeguard Security Team
3 min read

OpenSSH does not call liblzma. In the xz backdoor case, some distributions patched sshd to support systemd notification, libsystemd depends on liblzma, and so the compromised library ended up inside the SSH daemon. Andres Freund's public disclosure of the backdoor explains the whole path.

The chain of dependencies

Freund's 29 March 2024 post on oss-security lays out the route. Debian and several other distributions patch OpenSSH to support systemd notification. That support uses libsystemd, and libsystemd depends on liblzma. So the SSH server loads the xz library even though OpenSSH itself never uses it.

Draw it as a line: sshd, then libsystemd, then liblzma. Nobody reviewing sshd would see compression code in it. Nobody who installed xz for compressing archives would expect it to touch login.

What the injected code did, per the disclosure

Freund describes the backdoor replacing two function resolvers in liblzma and installing an audit hook in the dynamic linker. It redirected a table entry for RSA_public_decrypt so that the SSH signature check ran through its own code. He observed it running during a public key login, before authentication, though he had not worked out what it checked.

Systems built with -z now resolve symbols at startup, which let the code act before the table became read only. The injection applied to x86-64 Linux package builds using GCC and the GNU linker, and it did not appear in the upstream git tree, only in release tarballs of versions 5.6.0 and 5.6.1.

What it says about transitive dependencies

Software composition lists usually show your direct dependencies. This case sat three layers down, and it was reached through an operating system patch, not through a package manager manifest. Several lessons follow:

  • A package inventory for applications does not cover the system libraries your images and hosts load.
  • A single libraries-in-process view, such as which shared objects your daemon actually maps, shows things a manifest cannot.
  • Distribution patches change the dependency graph of upstream software. Upstream docs may not match what you run.
  • Early detection came from a performance symptom, not from a scanner. Freund noticed high CPU use in SSH logins and odd valgrind errors.

What to do on your own hosts

  1. Know which of your images and hosts ship the affected versions, 5.6.0 and 5.6.1.
  2. For critical daemons, list the shared libraries they load and check the list for surprises.
  3. Track the origin of your base images and how they are built.
  4. Watch login latency and CPU use on exposed services, since those are cheap signals.

For related posts see the xz CVE checklist and how the backdoor was found through slow logins.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how transitive packages appear beneath the ones you chose.

Quick check

Did OpenSSH itself contain the backdoor?

No. Per Freund, OpenSSH does not link liblzma directly. Exposure came through libsystemd in patched builds.

Was the injected code in the git repository?

Freund's post says the injected build script was in the release tarballs, not in the upstream git source of that file.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.