SUPPLY CHAIN

Rust Build Scripts Executed Malware From a Crate With 245 Million Downloads

A compromised maintainer account published malicious versions of arrayref, internment, and append-only-vec to crates.io on August 20, 2026. The payload lived in the build script of a typosquatted dependency, so compiling a project was enough to run it.

Matt Lucas  |  August 22, 2026  |  5 min
Editorial hero illustration
245,385,500
arrayref all time downloads
86 to 107 min
time the bad versions were live
403
crates depending on arrayref
4
OS and arch specific payloads
TL;DR
  • What: A compromised crates.io maintainer account published arrayref 0.3.10, internment 0.8.7, and append-only-vec 0.1.9, each adding a single dependency on proc-macro1, a typosquat whose build script downloaded and executed a remote payload at compile time.
  • Impact: arrayref has 245,385,500 all time downloads and 403 dependent crates, and the stage 2 implant persists on Windows, macOS, and Linux while stealing browser credentials from Chrome, Brave, and Edge.
  • Fix / mitigation: There is no CVE and no patched release: pin arrayref at 0.3.9 or earlier, which the Rust Security Response Team unyanked during the response, purge ~/.cargo/registry/cache, and block proc-macro1, proc-macro-en, aovine, arone, aronenao, and tinymember.
  • Who's at risk: Any developer workstation or CI runner that built, checked, or tested a Rust project resolving a caret range on arrayref 0.3.x between 07:15 and 09:26 UTC on August 20, 2026.

A compromised maintainer account on crates.io published malicious releases of three Rust crates on August 20, 2026. The lead crate, arrayref, has 245,385,500 all time downloads and 53,905,601 in the 90 days ending August 20. The malicious code did not live in the crate you called. It lived in the build script of an injected dependency, which means compiling a project that resolved the new version was enough to execute a remote payload. No function call required.

The Rust Security Response Team received the report at 07:15 UTC, credited to the Research Team at Nextron Systems GmbH, and deleted all three releases within 86 to 107 minutes. There is no CVE, no patched version, and no vendor fix to apply. The mitigation is version pinning and host inspection.

The three releases and the yank lure

Each compromised release carried exactly one added line in its manifest: a dependency on proc-macro1, a typosquat of the ubiquitous proc-macro2. The library source of proc-macro1 is a genuine copy of proc-macro2, so builds compiled clean and nothing downstream broke. The delivery trick is the part worth studying. Within the same minute as the malicious publish, the owner account yanked arrayref 0.3.5 through 0.3.9. That left 0.3.10 as the only version Cargo would not warn about, turning Cargo's own suggestion to update to a version that is not yanked into the lure. The reporter, GitHub user jhobern, said that is precisely how they hit it.

What the build script did

The build script reassembles its payload host and command and control address from base64 fragments at build time, so neither string sits in the source in a greppable form. It then installs a custom certificate verifier whose three verification methods return success unconditionally, disabling TLS validation for the download. It selects one of four payloads by operating system and CPU architecture.

On Unix and macOS it writes the bytes to /tmp/rust-setup, marks the file executable, and spawns it detached with the C2 address as the first argument. On Windows it drops a PowerShell script into %TEMP% and launches it hidden through a VBScript launcher under wscript.exe, then abandons the child process. A comment in the source describes that last step as escaping Cargo's job object so the build does not wait on the payload. The build finishes normally and the developer sees nothing unusual.

cargo build is not the only trigger

The Nextron analysis notes the crate can fire on cargo build, cargo check, and cargo test. Any editor running cargo check on save, or any CI job that runs tests on push, would have executed the payload without anyone asking for a release build.

Blast radius

403 distinct crates on crates.io depend on arrayref, and the transitive reach is wider than that number suggests. One verified chain runs winit requires sctk-adwaita ^0.10.1, which requires tiny-skia ^0.11, which requires arrayref ^0.3.6. Every requirement in that chain is a caret range on 0.3.x, and a caret range on 0.3.x accepts 0.3.10. Any project in that graph without a committed lockfile, or running a dependency update inside the 86 minute window, would have resolved the malicious version.

Several major consumers cut the dependency the same morning. blake3 declared arrayref through 1.8.6 and does not in 1.8.7, published at 09:09 UTC. blake2b_simd and blake2s_simd dropped it in releases published at 09:25 and 09:26 UTC.

The stage 2 implant

Wiz reports the second stage beacons over HTTPS POST to the path /49890878 and supports four commands: terminate, reconfigure the C2, install persistence, and download and run further scripts. Persistence is per platform: a Registry Run key on Windows, a LaunchAgent on macOS, and a systemd user service on Linux. Wiz says it steals browser credentials from Chrome, Brave, and Edge by querying the SQLite login databases.

The Nextron analysis adds a limit worth carrying into triage. It covered the Windows stage only. That stage queries the origin_url and username_value columns and does not directly extract password_value. The Linux and macOS payloads were hashed but not analysed, so assume full credential theft on those platforms until someone publishes otherwise.

Indicators and immediate actions

The evidence gap

RustSec advisories for all three crates record no evidence that any malicious version was used, but the Rust Security Response Team has not published download counts for the deleted releases or the basis for that finding. No evidence of use is not proof of no use. Verify against your own build logs and hosts rather than inheriting the conclusion.

Why this one justifies a policy change

The maintainer is not the attacker. The Rust Security Response Team said it does not believe the arrayref author acted maliciously and that their computer or credentials are likely compromised. The sole listed owner of arrayref is a single account registered in October 2009. How it was taken over has not been disclosed.

That is the structural problem. A quarter billion downloads and 403 dependent crates ran through one account's credentials, and build scripts execute arbitrary code with the developer's privileges by design. Two controls actually blunt this: commit your Cargo.lock and refuse unreviewed dependency bumps, and run builds in an environment where a build script cannot reach the internet or the developer's home directory. Neither one depends on a registry catching the next campaign in 86 minutes.

Questions about your exposure?

RedEye Security provides assessments for organizations that need to understand their real risk.

Talk to us