On August 20, 2026, a compromised release of the popular Rust cratearrayrefappeared on
crates.io. Version 0.3.10 added a dependency on a typosquatted crate calledproc-macro1, whose build script downloads and runs a remote binary while a project compiles.
The code runs at build time, so simply compiling a project that pulled the bad versions is enough
to trigger it. The crates.io team has since removed the malicious versions.
The genuinearrayrefandappend-only-veccrates are maintained bydroundy, whose account
appears to have been compromised. The corresponding GitHub repositories are no longer available.github.com/droundy/arrayref,github.com/droundy/append-only-vec, and the entiregithub.com/droundyaccount all return 404,
so the upstream code is no longer available for inspection. A separate account,dtolney, publishedproc-macro1.
The username closely resembles David Tolnay’s realdtolnayaccount. Its metadata forgesauthors = [“David Tolnay “]and pointsrepositoryat adtolnay/proc-macro1path that returns 404.
Note thatproc-macro1is notproc-macro2. The real crate that macro authors depend on isproc-macro2. Thesrc/of the maliciousproc-macro1is a genuine copy ofproc-macro2, so builds kept working while the build script ran.
The payload lives in the build script ofproc-macro11.0.107. It stores its server address as
base64 fragments and reassembles them at build time, quoted in the advisory:
Decoded, those fragments produce the payload hosthxxps://23[.]254[.]165[.]112:9089/and the
command and control address23[.]254[.]165[.]112:443. The script fetches an architecture-specific
binary over a TLS connection that accepts any certificate without validation, then runs it detached
from the build. On Unix it drops and runs/tmp/rust-setup. On Windows it writes a PowerShell
script and a VBScript launcher under%TEMP%and starts them hidden, then abandons
the child process so the compiler does not wait for it.
The owner account yanked the olderarrayrefreleases 0.3.5 through 0.3.9. Yanking a
crate makes Cargo print a “consider updating to a version that is not yanked” warning, which nudges
developers toward the only non-yanked release, the malicious 0.3.10. The reporter who filed theRustSec advisorynoted this is how they hit
it.
arrayrefis widely used as a transitive dependency. It sits deep in common Rust graphs throughtiny-skia,sctk-adwaita, andwinit, which places it under most GUI work built on egui,
eframe, and iced. The crate has about 245 million all-time downloads (244,989,384 at time of
writing), with the clean 0.3.9 release accounting for roughly 152 million. Those numbers measure
how widely the crate is used rather than a count of affected builds.
SHA256 of the removed crate artifacts:
Our technical analysis covers the two crates behind this incident,arrayref0.3.10 andproc-macro11.0.107.arrayref0.3.10 pulls in a dependency calledproc-macro1. The malicious
code is in the build script ofproc-macro1, not inarrayrefitself.
arrayrefis a small crate of four macros. Up to 0.3.9 it has no build script and no runtime
dependencies. Version 0.3.10 keeps that macro source and adds one line to the manifest:
This[dependencies.proc-macro1]entry is sufficient to introduce the malicious crate. The requirement1.0.107is a caret
range, and with only 1.0.106 and 1.0.107 ever published it resolves to the malicious 1.0.107. The
crate’s ownsrc/lib.rsis the ordinary macro code, for example thearray_ref!macro:
Nothing in thearrayrefsource referencesproc-macro1, and it does not need to. Cargo builds
every declared non-optional dependency, whether or not the code uses it. So the manifest entry alone
makes Cargo fetch and buildproc-macro1whenever a project pulls inarrayref0.3.10, and building
it runs the malicious build script.