After xz: Supply-Chain Trust When Code, Models and Contributors Are Unknown
The xz backdoor hid in a release tarball, malicious models hid in pickle files, and AI agents are starting to open pull requests. One supply-chain checklist covers all three.

On March 29, Andres Freund posted to the oss-security list that the upstream xz repository and its release tarballs had been backdoored, in versions 5.6.0 and 5.6.1. He found it because SSH logins on his Debian sid machines were using unusual amounts of CPU and valgrind was reporting errors. A failed login that used to take about 0.3 seconds was taking about 0.8.
Half a second of latency is what stood between a compression library and a backdoor in sshd. The affected versions had not yet been widely adopted by distributions. That was luck, not process.
Seven weeks on, the lesson for operators is broader than one library. The number of things we pull into production without really knowing who made them is growing fast, and xz is the clearest picture yet of how that goes wrong.
What xz actually exploited
The details are worth reading in full, because each one defeats a control many teams rely on:
- The tarball was not the repository. The malicious build step lived in
build-to-host.m4in the release tarballs, not in the upstream git source. Anyone who reviewed the repo and built from the tarball reviewed the wrong thing. - The payload hid in test files. Obfuscated data was committed under
tests/files/, where binary blobs look normal. - It only fired in specific builds. The injection targeted x86-64 Linux builds using gcc and GNU ld, packaged as Debian or RPM, which made it harder to spot anywhere else.
- It came through the project's own release process. A checksum only proves you received what the project published, and here the project's own release was the problem.
Pinning a version would not have helped you if you pinned 5.6.1. Knowing where that version was running, quickly, would have.
Models are code you execute
In late February, JFrog reported around 100 malicious models on Hugging Face. One used Python's pickle __reduce__ mechanism inside a PyTorch model file, so simply calling torch.load() opened a reverse shell to a remote IP. No inference needed. Loading the file was enough.
Many teams still treat model weights as data: download from a public hub, cache in a bucket, load in a notebook with production credentials nearby. A pickle-based model is an executable. It deserves the same intake process as any other third-party binary.
Agents are new contributors
In March, Cognition introduced Devin, reporting that it resolved 13.86% of issues end-to-end on a random 25% subset of SWE-bench, against a previous state of the art of 1.96%. At the end of April, GitHub opened a technical preview of Copilot Workspace, which takes an issue, proposes a plan, generates the code changes and lets you run tests in a Codespace before you open a pull request.
Both are early, and both point the same way: more changes arriving from a contributor you did not hire, cannot interview and whose context you cannot fully see. That is not a reason to avoid them. It is a reason to make sure your pipeline does not assume every commit came from a trusted human who understood the code.
One checklist for code, models and agents
The same few controls cover all three sources of risk:
- Build from what you reviewed. Build dependencies you vendor from tagged source where you can, or diff release tarballs against the tagged commit.
- Pin by hash, not by name. Lockfiles with integrity hashes, container images by digest, and models by commit revision rather than
main. - Keep an SBOM per artifact. Generate it in CI and store it with the release, so "where are we running xz 5.6.x?" takes minutes, not days.
- Record provenance. Sign build outputs and keep attestations of what source and builder produced them.
- Gate model intake. Prefer safetensors, scan pickle files before use, and load anything untrusted in a sandbox with no credentials and no outbound network.
- Limit build egress. A reverse shell needs a way out. CI runners and training jobs should only reach the registries they need.
- Treat agent output as untrusted input. Label agent-authored pull requests, keep the same branch protections and required reviews, and never give the agent's environment production secrets or merge rights.
What we recommend
Pick one production service this month and run a tabletop: a critical dependency was backdoored yesterday. How long does it take to find every place it runs, rebuild without it and prove the new artifact is clean? The gaps you find are your roadmap.
Then put models and agent output on the same intake path as packages. One process is easier to audit than three.
If you would like a hand building that pipeline, the HAZL Solutions team works on exactly this kind of supply-chain plumbing.