On August 20 at 7:15 UTC, the Rust Security Response Team got a report: a popular crate had been compromised, and a typosquatted dependency was downloading and running remote binaries during compilation.
By 8:41 UTC — 86 minutes later — the malicious versions were deleted from crates.io. The account was locked. The legitimate versions were restored. But in that window, someone's computer was compromised, and the Rust ecosystem learned what npm has known for years: supply chain attacks don't require elegant exploits — they just need a build script and a misspelled name.
The Attack
Here's the chain, as reconstructed by the SafeDep research team and confirmed by the Rust team:
graph LR A[arrayref v0.3.10
compromised] -->|adds dependency| B[proc-macro1 v1.0.107
typosquat] B -->|build.rs runs| C[Downloads remote binary
over unverified TLS] C --> D[Linux: /tmp/rust-setup] C --> E[Windows: PowerShell via WScript] C --> F[macOS: /tmp/rust-setup] D --> G[C2: argv[1] passed to payload] E --> G F --> G style B fill:#5c1a1a,stroke:#ef4444
The genuine arrayref crate — 245 million all-time downloads, maintained by David Roundy (the creator of DARCS) — had its account compromised. Version 0.3.10 added one line to Cargo.toml that wasn't in 0.3.9:
[dependencies]
proc-macro1 = "1.0.107"
The typosquat is surgical. The real crate is proc-macro2 (by David Tolnay, 1.2B downloads). The fake is proc-macro1 — one character off. And here's the evil part: proc-macro1 is a mechanical find-and-replace of proc-macro2's source. Every function, every export, every doc link is renamed. So the crate compiles successfully. Your build succeeds. Nothing looks wrong. But while it compiles, the build script is already running.
The Mechanics
The build script's dependencies are the first red flag: base64, rustls, ureq. A token-parsing library has no business bundling a TLS stack. But since it's a build dependency, cargo audit won't flag it unless someone specifically audits the dependency tree end-to-end.
The script splits the C2 server address into base64 fragments and reassembles them at compile time — a trivial obfuscation that defeats naive string scanning.
On Unix systems, it writes the fetched binary to /tmp/rust-setup, chmods it executable, and spawns it detached with the C2 URL as argv[1]. On Windows, it's more creative:
// ShellExecute via WScript escapes Cargo's job object;
// spawned children otherwise keep the build script
// (and `cargo build`) waiting until they exit.
r#"CreateObject("Wscript.Shell").Run
"powershell.exe -NoProfile ... -File \"{script}\" \"{end}\"", 0, False"#
The VBScript launcher escapes Cargo's job object, meaning the PowerShell payload keeps running long after cargo build finishes. The compiler never waits for it. The user never sees it.
The payload supports four targets: Linux x86_64, Windows x86_64, macOS x86_64, and macOS ARM. Each variant is fetched by a separate binary name (rust-crate_0.1.0 through rust-crate_0.3.0).
The Response
Once reported, the Rust Security Response Team moved fast. The malicious versions were online for:
arrayref@0.3.10— 90 minutesproc-macro1@1.0.107— 86 minutesappend-only-vec@0.1.9— 107 minutes (same compromised author)internment@0.8.7— also affected
All malicious versions were deleted. The legitimate versions were unyanked. The account was locked pending contact with the maintainer. The Rust team does not believe David Roundy is acting maliciously — his account was compromised.
Check your local cache:
ls ~/.cargo/registry/cache/*/{arrayref-0.3.10,append-only-vec-0.1.9,internment-0.8.7,proc-macro-en-*}.crate 2>/dev/null
What This Means
The Rust community has spent years telling everyone that memory safety prevents entire classes of vulnerabilities. That's true. But it's irrelevant here. The vulnerability isn't in the code you write. It's in the code you depend on.
Three things this attack exposes:
- Cargo has no sandboxing for build scripts.
build.rshas access to your network, filesystem, environment variables (including$CARGO_HOMEand SSH keys), and child processes. There's been discussion about sandboxed builds since 2024 (RFC 3923), but it's still not shipped. npm tools like pnpm have had installer allowlisting for years. - Min-publish-age would have stopped this. If crates.io required a 24-hour waiting period for new versions, the typosquat would have been noticed by static analysis before it could propagate. npm has had this for years too.
- Trusting the crate, not the author. The real takeaway: you're not trusting
arrayref, you're trusting that David Roundy's laptop hasn't been compromised. That's a much larger attack surface than any code review.
Bottom Line
The Rust ecosystem is now squarely in the same boat as npm. The same attack vectors, the same tradeoffs between convenience and security, the same mourning period where the community discovers that "but we're Rust, we're safe" doesn't apply to the build process itself.
The good news: the response team was fast (86 minutes to takedown). The advisory database is mature. The conversation about sandboxing is active. The bad news: this won't be the last one. The economics of supply chain attacks are too good — one compromised laptop, one well-placed typosquat, and you have execution on every machine that runs cargo build — including CI pipelines, production build servers, and developer workstations with access to production.
If you're building in Rust today, audit your dependency tree. And if you're running cargo build on a machine with production credentials, ask yourself: do I trust every single crate in my tree's transitive dependencies? Because the answer is probably no, and now you know it.
- Supply Chain Attack on Arrayref — Rust Blog, 2026-08-20
- Malicious Rust Crate arrayref Runs a Build-Time Payload — SafeDep, 2026-08-20
- HN Discussion (510 points, 432 comments) — Hacker News, 2026-08-20
- Cargo RFC #3923 — min-publish-age — GitHub
- Rust 2024 Goal: Sandboxed Build Scripts — Rust Foundation