Open Source ·

arrayref crates.io account published build-script dropper dependency

A compromised crates.io account republished arrayref, internment, and append-only-vec on 2026-08-20 with a dependency on the typosquat proc-macro1, whose build script downloaded and ran a second stage at compile time. The releases stood 86 to 107 minutes.

At 07:15 UTC on August 20, 2026, someone using the crates.io account of David Roundy, who has maintained the Rust crate arrayref since 2015, published version 0.3.10. The library source did not change by a single byte. What changed was one line of the manifest, and that line was enough to run code on every machine that compiled it.

arrayref is a small set of macros that let a Rust program take a fixed-size array reference out of a slice. It is the kind of dependency nobody thinks about: 245 million downloads over its lifetime, beneath blake3, tiny-skia, libsecp256k1, and a long tail of Solana and Ethereum tooling. The new manifest added proc-macro1 = "1.0.107". That crate is not proc-macro2, the near-universal macro library written by David Tolnay; it was a copy of it, published five hours earlier that morning by an account named dtolney, created at 01:17 UTC the same night, and carrying a forged author line reading David Tolnay <[email protected]>. Everything in it was genuine proc-macro2 code except build.rs, and Cargo runs build.rs during compilation, before any of the library's own code is ever called.

The build script reassembled a URL from five base64 fragments, which decode to https://23.254.165.112:9089/, and fetched a platform-specific binary named rust-crate_0.1.0 through rust-crate_0.4.0 for Linux, Windows, and both macOS architectures. It did so over TLS with a certificate verifier that approved every certificate presented to it. On Unix the payload was written to /tmp/rust-setup, made executable, and spawned with its output discarded and the C2 address 23.254.165.112:443 as its only argument. On Windows the script was dropped to %TEMP%\rust-setup.ps1 and launched through a rust-setup-launch.vbs shim under wscript.exe, then forgotten with std::mem::forget so it would outlive the job object Cargo uses to reap build-script children. The build then finished normally and printed nothing unusual. StepSecurity and Wiz reported the second stage as an implant that harvested credentials from Chrome, Brave, and Edge profiles, persisted through systemd units, LaunchAgents, and Registry Run keys, and beaconed to /49890878 on Hostwinds infrastructure.

The attacker also yanked arrayref 0.3.5 through 0.3.9 in the sixteen seconds after publishing, a detail preserved in the crates.io index commits. A yank does not remove a version, but it does make Cargo warn about it, and the natural response is cargo update, which would have resolved to 0.3.10. The same account republished internment 0.8.7 at 07:34 and append-only-vec 0.1.9 at 07:37 with the same dependency. The Rust Security Response working group received a report about proc-macro1 at 07:15 UTC, credited in the project's write-up to the research team at Nextron Systems GmbH, and deleted the malicious crates, locked the accounts, and reversed the attacker's yanks. arrayref 0.3.10 was gone 86 minutes after it appeared, having been downloaded 2,285 times. The Rust team said it did not believe the maintainer had acted maliciously and that his computer or credentials were likely compromised; no commit or tag for 0.3.10 ever existed in the repository, and the published crate lacked the .cargo_vcs_info.json file Cargo writes when publishing from a git checkout. Wiz found the beacon path, the TLS certificate issuer, and the 23.254.164.0/23 address range shared with the Mastra npm compromise that Microsoft attributed to the North Korean actor Sapphire Sleet, and with the axios attack Google linked to UNC1069.

Notes

  • crates.io deletes malicious releases rather than yanking them, and its API and CDN then answer 403. All four crate files were recovered from regional mirrors, each digest matching the cksum in the crates.io-index git history.
  • The clean decoy proc-macro1 1.0.106 was not held by any mirror that was asked and remains unrecovered.
  • No remediated release exists for any of the three legitimate crates. crates.io restored the prior versions by reversing the attacker's yanks, so the remediated state is byte-identical to the before samples.

Appendix · Affected releases

arrayref crates.io fixed 0.3.9
0.3.10 sha256 25ad7009…9a9373ae download unavailable
internment crates.io fixed 0.8.6
0.8.7 sha256 ee71e794…2902d291 download unavailable
append-only-vec crates.io fixed 0.1.8
0.1.9 sha256 48eb1339…41cc9416 download unavailable
proc-macro1 crates.io
1.0.106 no sample yet
1.0.107 sha256 61198155…831b34d4 download unavailable

Indicators

  • urlhttps://23.254.165.112:9089/
  • ip23.254.165.112
  • ip23.254.167.107
  • ip23.254.167.216
  • domainhwsrv-798836.hostwindsdns.com
  • file/tmp/rust-setup
  • filerust-setup.ps1
  • filerust-setup-launch.vbs
  • filerust-crate_0.1.0
  • fileMonoService
  • fileMonoXpc
  • file$HOME/.config/AzureKits
  • file$HOME/.config/ServiceKit
  • url/49890878
  • accountdtolney

References

  1. Supply chain attack on arrayrefblog.rust-lang.org
  2. RUSTSEC-2026-0260 arrayref 0.3.10 removed from crates.iorustsec.org
  3. RUSTSEC-2026-0265 proc-macro1 removed from crates.iorustsec.org
  4. arrayref Rust crate supply chain attackstepsecurity.io
  5. Rust supply chain attack on arrayref shows significant overlap with DPRK campaignswiz.io
  6. The arrayref supply chain attackcompilersutra.com

Source record: oss/attacks/arrayref/meta.yaml