On August 20, 2026, malicious versions of three unrelated but commonly-used Rust crates — [email protected], [email protected], and [email protected] — hit crates.io from the same compromised maintainer account. All three added a single new dependency: proc-macro1, a typosquat of the widely used proc-macro2 crate. Because the malicious code lives in a build script rather than the crate’s runtime logic, it executes the moment a project compiles, not when the library’s functions are called.

What happened

The Rust Security Response Team and researchers at StepSecurity, Semgrep, and Wiz reconstructed the timeline: all three poisoned releases were published from the same account within roughly 23 minutes and pulled from crates.io between 86 and 107 minutes later. The legitimate maintainer is not believed to have acted maliciously — the Rust Security Response Team assessed the account’s credentials or machine as compromised and locked it as a precaution.

arrayref alone has more than 245 million lifetime downloads as a low-level byte-slicing utility pulled in transitively across a huge swath of the Rust ecosystem; internment and append-only-vec add close to 19 million combined downloads. Because arrayref is transitive in many dependency trees, a large share of affected builds likely came from projects that never directly depend on the poisoned crates at all.

Technical details

proc-macro1 is a typosquat of proc-macro2, a foundational crate with 150M+ downloads used by nearly every proc-macro-based library in the ecosystem. The name is one character removed from the legitimate crate and easy to miss in a Cargo.toml diff or a quick dependency-tree scan.

The payload lives in build.rs, which Cargo executes automatically — no explicit opt-in required. Any of cargo build, cargo check, or cargo test against a project that transitively depends on the malicious release triggers it. Researchers found the malicious build.rs byte-for-byte identical across all three poisoned crates, indicating a single dropper reused against multiple targets rather than three independent compromises.

At build time, the script reconstructs an obfuscated download URL from Base64-encoded fragments (evading naive string scans of the source), instantiates a TLS client that accepts any certificate, and downloads a payload matched to the host’s OS and CPU architecture. On Unix hosts it writes the payload to /tmp/rust-setup, marks it executable, and launches it detached. On Windows it drops %TEMP%\rust-setup.ps1 alongside a VBScript launcher invoked through wscript.exe with CREATE_NO_WINDOW, avoiding a visible console window.

Wiz’s analysis of the recovered Windows payload found a PowerShell backdoor with host/OS profiling, enumeration of installed applications, inspection of Chrome/Brave/Edge profiles for saved logins and extension data, persistence, a domain-generation-algorithm (DGA) fallback for C2 resilience, and the ability to execute arbitrary remote PowerShell.

No CVE has been assigned; this is an account-compromise and typosquat event, not a vulnerability in the crates’ own code.

Attribution

Wiz reports the campaign’s infrastructure overlaps with recent DPRK-attributed supply-chain campaigns, including the Mastra and axios incidents: the arrayref payload beacons to the same C2 request path used in the Mastra campaign, the beacon endpoint’s TLS certificate shares an issuer with a known Mastra-campaign host, and a victim-reported C2 address from this incident appears in threat-intel coverage of a North Korean actor’s separate axios-targeting campaign. Attribution is not yet confirmed by a government or vendor consensus, but the infrastructure reuse is a strong signal.

Impact

Anyone who ran cargo build, cargo check, or cargo test against a project pulling arrayref 0.3.10, internment 0.8.7, or append-only-vec 0.1.9 (directly or transitively) between publication and removal on August 20 should treat the build host as compromised. CI runners are the highest-value target here: build-time execution means a CI job that merely compiles a dependency tree — with no test execution, no application code run — is enough to trigger the payload and expose whatever credentials, cloud tokens, or SSH keys are reachable from that runner.

Given arrayref’s footprint as a transitive dependency across the ecosystem, the population of builds that resolved one of the three malicious versions during the exposure window is larger than the direct-dependent count suggests, and may not be fully known yet.

Mitigation

  • Check Cargo.lock files and CI build logs for arrayref 0.3.10, internment 0.8.7, append-only-vec 0.1.9, or any dependency on proc-macro1 (there is no legitimate crate by that name — its presence in a lockfile is itself an indicator of compromise).
  • If any of these versions resolved on a build host or CI runner during the exposure window, treat that host as compromised: rotate credentials, tokens, and SSH/GPG keys reachable from it, and inspect for the Unix (/tmp/rust-setup) or Windows (%TEMP%\rust-setup.ps1, rust-setup-launch.vbs) payload artifacts.
  • Pin dependencies via Cargo.lock and audit lockfile diffs in CI, particularly for new transitive dependencies appearing on an unrelated crate’s minor/patch bump.
  • Use cargo vet or cargo-crev to gate new or updated dependencies before they reach a build pipeline, and consider running untrusted builds in ephemeral, network-restricted sandboxes so a build.rs payload has nothing to phone home to and nothing durable to persist on.
  • Treat single-character typosquats of high-download foundational crates (proc-macro2, syn, quote, etc.) as a standing detection rule, not a one-off IOC.

Advisories and technical breakdowns: Rust Blog, The Hacker News, Wiz, StepSecurity, Semgrep, BleepingComputer.