On 20 August 2026 the Rust Security Response Team removed malicious releases of three crates: arrayref 0.3.10, internment 0.8.7 and append-only-vec 0.1.9. Each had been republished to depend on a lookalike crate, proc-macro1, which imitates proc-macro2. Its build script downloaded and ran a payload on the machine that compiled the code.
The Rust team says it does not believe the maintainer acted maliciously, and suspects the author's computer or credentials were compromised. The account was locked. Socket's scanner flagged proc-macro1 at 07:29 UTC, minutes after the first republish.
What's affected
| Crate | Malicious version | Published (UTC) | Deleted | Online |
|---|---|---|---|---|
| arrayref | 0.3.10 | 07:15 | 08:41 | about 86 minutes |
| internment | 0.8.7 | 07:34 | 09:04 | about 90 minutes |
| append-only-vec | 0.1.9 | 07:37 | 09:25 | about 107 minutes |
Safe versions per Socket: arrayref 0.3.9 or earlier, internment 0.8.6 or earlier, append-only-vec 0.1.8 or earlier. The attacker also yanked several older legitimate arrayref releases, which may have steered resolution toward 0.3.10. Rust later restored them.
Deleted attacker crates: proc-macro1, proc-macro-en, aovine, arone, aronenao and tinymember (the last impersonated tiny-skia). Socket reports arrayref had roughly 152 million downloads of the prior clean release, according to RustSec.
How the build script works
Cargo runs build.rs automatically when it compiles a crate or any of its dependencies. Your application never calls the code, and tests and cargo check run it too. Socket describes the loader as reconstructing Base64-obfuscated server addresses, detecting the OS, disabling TLS verification and downloading a platform-specific binary.
On Linux and macOS it wrote /tmp/rust-setup. On Windows it dropped rust-setup.ps1 and rust-setup-launch.vbs in %TEMP% and launched hidden PowerShell. The backdoor profiled the host, inventoried Chromium browser login origins, set up persistence (a Run key, a systemd user service or a LaunchAgent), and accepted commands. It can run scripts and shell commands. Socket says the analyzed stage did not decrypt stored passwords.
What the second stage does
Socket's analysis of the second stage adds a few details useful for hunting:
- The beacon goes to a path ending in
/49890878on the command server, and the payload accepts commands to change its configuration, persist, download and run scripts, and exit. - When the main server is unreachable it falls back to ten date-based
.comdomains. Socket published the list for 20 to 24 August 2026 as hunting indicators, noting they are not necessarily registered. - The payloads do not embed the server address.
proc-macro1hands it over at runtime, so a payload found on disk will not name its server. - Socket reports the same RSA private key is embedded across payloads, and command authentication does not guarantee a single operator.
- Linux x86-64, Windows x86-64, macOS x86-64 and macOS ARM64 builds were served, each from its own download path.
The incident was reported to the Rust Security Response Team by Nextron Systems, and the advisory went to RustSec as well.
How to check if you're exposed
grep -nE 'name = "(arrayref|internment|append-only-vec|proc-macro1|proc-macro-en|aovine|arone|aronenao|tinymember)"' -A1 Cargo.lock
find ~/.cargo/registry/cache -name 'arrayref-0.3.10.crate' -o -name 'internment-0.8.7.crate' -o -name 'append-only-vec-0.1.9.crate'
ls /tmp/rust-setup 2>/dev/null
Search CI build logs, caches and internal mirrors for the same names. Hunt in network logs for connections to 23.254.165.112 on ports 9089 and 443. On Windows hosts look for rust-setup.ps1, rust-setup-launch.vbs, unexpected Run keys and wscript.exe activity tied to Cargo builds.
What to do now
- Pin
Cargo.lockto safe versions and runcargo update -p arrayref --precise 0.3.9(and the same for the other two). - If a host built a malicious version, treat it as compromised. Check for persistence created after the build, then rebuild from a clean system.
- Rotate credentials and secrets that were available to that build environment.
- Purge the malicious
.cratefiles from caches and internal mirrors. - Rebuild any release artifacts that were compiled during the window.
How this could have been avoided
- Treat a new dependency in a patch release as a review event.
arrayref0.3.10 addedproc-macro1. A lockfile diff bot or a CI check that fails on new dependencies in patch updates would have flagged it. - Commit
Cargo.lockand build with--lockedfor applications, so a fresh republish cannot enter without a commit. - Run builds in a sandbox without network access after fetching sources with
cargo fetchorcargo vendor. The loader needed to download its payload at build time. - Restrict egress from build hosts to your registry mirror and known domains. A raw IP on port 9089 stands out.
- Cooldowns. All three releases were removed within two hours, and a delay of even a day would have missed them.
Why it matters
Cargo has no npm-style install scripts, and people sometimes assume that removes this class of attack. Build scripts run arbitrary code on the build machine. Here the malicious code sat one dependency away from a crate with roughly 152 million downloads.
The window was short, but the damage depends on who built in it. Teams that update on a schedule, pull fresh dependencies in CI, or build containers on a laptop between 07:15 and 09:25 UTC on that day are the ones to check.
There is also a lesson in how fast the response went. The first report reached the Rust team at 07:15 UTC, the same minute arrayref@0.3.10 went live, and the last deletion came at 09:25. Registries cannot prevent every compromised laptop, but quick reporting limited the exposure to under two hours.
Try it yourself
Pick one Rust service and diff Cargo.lock between your last two release commits. List every crate that gained a dependency. For each, check that its upstream repository has a matching commit and tag. A release with no matching source change is the pattern here.
Click through it at your own pace, or open it full screen.
Quick check
Why did the application never need to call the malicious code?
Cargo runs build.rs automatically when compiling a dependency, so the loader runs at build time.
Which signal would have caught the arrayref release earliest?
A new dependency, proc-macro1, appearing in a patch release with no matching source change upstream.