Cargo pulls hundreds of transitive dependencies and runs their build scripts on your runner as whatever user Rust happens to be. (Reassuring, isn't it.) This week that trust boundary got tested in public. DevOps.com reports that attackers took over the maintainer account behind the arrayref Rust crate and used the access to publish four additional attacker-owned crates loaded with information-stealing malware. Wiz researchers, per the same report, tie the campaign to overlap with nation-state supply-chain activity.
You should already have assumed this could happen. The interesting part is what your pipeline is doing about it.
Where the trust actually failed
The technical detail worth noticing is the direction of the attack. Nobody had to smuggle a malicious PR past a code review. Nobody had to slip a typosquat past a sleepy developer. Somebody logged in as the maintainer and pushed. Whatever crates.io had between "signed in" and "release published" was the entire trust boundary, and this week it was one factor short.
Every ecosystem has this hinge. npm has it. PyPI has it. RubyGems has it. crates.io is not unusually reckless here; it is representative. If your defence-in-depth stops at "we trust the registry", you have one lock protecting your build farm and the key is a phishable password.
What cargo audit and cargo vet can and cannot see
If you have hardened your Rust builds, you probably reach for two things. cargo audit compares your lockfile against the RustSec advisory database. cargo vet records human review of specific crate versions. Both are useful. Neither would have caught this on day one.
cargo audit is downstream of somebody filing the advisory. In a live compromise, the malicious version sits on the registry before it lands in the database, and you learn about it on whatever timeline the researchers publish on. cargo vet fares better in principle, because a new version from a compromised maintainer shows up as unreviewed. But vet only works if you gate CI on it and if your team is willing to say no to an unvetted release under deadline pressure. In practice, most teams add cargo vet, watch it flag things for a while, and then quietly stop reading the output.
The build script problem nobody wants to fix
Here is the sharper edge. Cargo lets crates ship build.rs scripts that execute at compile time. That is by design, and it is how a lot of the ecosystem works: bindings, code generation, feature detection. It is also why "we pinned the lockfile" is not enough on its own. A pinned, malicious build.rs still runs on your CI runner the first time you compile it, and it runs with whatever secrets that runner is allowed to see.
The mitigations here are unglamorous:
- Run cargo builds on ephemeral runners with no long-lived credentials in scope. If your CI runner sees your production deploy key at build time, you have a problem that predates any specific compromise.
- Egress-filter the runner. A build script that phones home to an unknown host should not be able to reach it.
- Cache and mirror the registry through a controlled proxy so you have a chokepoint to detect a bad version and roll back to a known-good one.
- Treat every dependency bump as a change that could execute code on your infrastructure, because it can.
None of that is Rust-specific. None of it requires the registry to fix anything.
How other registries are moving on the same shape
npm has been quietly moving in the opposite direction from Rust: recent releases disable lifecycle scripts by default, which shrinks the equivalent of build.rs blast radius on npm install. PyPI now offers trusted publishers backed by short-lived OIDC tokens, so a stolen maintainer password is worth less than it used to be. Sigstore-style keyless signing exists across ecosystems, and mostly is not required by default. The pattern is the same everywhere. The primitives to make a maintainer takeover survivable exist. They are opt-in. Most projects have not opted in.
crates.io will patch what it can on the account side. What matters more is whether your pipeline treats the registry as a trusted party or as an internet stranger you compile with root.
Pick one. The attackers already have.
Top comments (0)