Supply Chain

arrayref: 86 Minutes of Compromise

Key takeaways
  • On August 20, 2026, poisoned versions of the Rust crates arrayref, internment, and append-only-vec were published to crates.io from one compromised maintainer account.
  • The malware ran through a typosquatted dependency whose build script downloaded and executed a second-stage infostealer. Simply compiling the project was enough to be compromised.
  • The versions were live for around 86 minutes before crates.io removed them.
  • Researchers at Wiz reported infrastructure overlap with earlier DPRK-linked campaigns against the npm and JavaScript ecosystems. This is not a Rust problem. It is a registry-agnostic playbook that has now hit npm, PyPI, and crates.io.

What actually happened

At 07:15 UTC on August 20, 2026, arrayref 0.3.10 appeared on crates.io, and within about 23 minutes, poisoned releases of internment 0.8.7 and append-only-vec 0.1.9 appeared. From the outside, everything looked like regular point releases of trusted packages. The attacker even redirected older, secure version ranges so that anyone resolving these crates got the poisoned version.

Here's how the payload was delivered: the poisoned crates silently added a new dependency called proc-macro1, which is a typosquat of proc-macro2, one of the most widely used crates in the entire Rust ecosystem. The fake package copied the description of the real crate and even impersonated its known author to pass itself off as authentic. Its build.rs file was a cross-platform dropper: it downloaded a second-stage binary file from an attacker-controlled VPS via TLS with certificate validation intentionally disabled, saved it to a temporary directory, and executed it with the command-and-control address passed as an argument.

The second stage was information theft. It gathered host information and credentials, including login credentials retrieved directly from SQLite databases used by Chrome, Brave, and Edge browsers. None of this required the victim to use the infected crate. It merely required building a project that depended on it.

To put the blast radius into context: arrayref is a small, lightweight array conversion tool with approximately 245 million downloads. According to Aikido's analysis, it resides in about three-quarters of all environments where Rust is present under base crates like winit, egui, iced, and blake3, and within parts of Solana and Ethereum tools. Most developers who encountered this issue never heard of it because they never chose it. The official record is the Rust Security Response Team advisory (RUSTSEC-2026-0260).

Is it a pattern or an incident?

It's tempting to chalk this up to "Rust having a bad day" but that overlooks what the evidence actually points to.

Wiz reported that the infrastructure behind this campaign overlaps with previous supply chain attacks linked to the DPRK, encompassing operations against the JavaScript ecosystem, down to a beacon path used repeatedly in various campaigns. Investigators also discovered that proc-macro1 wasn't unique: a small group of related typosquat packages was published and then removed. In other words, the same operators are carrying out the same attack against any registry that's convenient this month: npm, then PyPI, and now crates.io.

The technique is portable because the weakness is structural, not language-specific. Every modern package ecosystem allows for the execution of third-party code during installation or compilation: npm lifecycle scripts, Python setup.py, Rust build.rs. This is a feature developers rely on. This is the exact same primitive mechanism these campaigns are using, because it turns "add a dependency" into "run this attacker's code on a developer's laptop or continuous integration runner with production privileges."

If you defend the ecosystem you're currently using and treat every incident as if it were someone else's problem, you'll be constantly surprised. The core of the problem is the build pipeline, and that does not change with the language you're writing in.

What to actually do about it

None of these patches are exotic. They're boring controls that this type of attack is specifically designed to bypass, and that's why they're so important.

  1. Pin and freeze. Commit the lock file and build with the --locked/--frozen flags to prevent a surprise point release from leaking into an unchecked build. A poisoned patch version will only help an attacker if the builds silently accept it.
  2. Provide or mirror your dependencies. Building against a checked mirror, rather than fetching data from a public registry with each CI run, reduces the exposure window to zero for the builds that matter most.
  3. Treat CI like a production environment. The privileges that make it worthwhile to deploy a stealer typically reside in the pipeline, not on the laptop. Least-privilege build tokens, short-lived permissions, and egress controls in runners make a successful breach significantly cheaper.
  4. Be wary of compile-time execution, not just known bad versions. A build script that connects to the network, disables certificate validation, or saves and executes a binary is suspicious, regardless of whether a CVE already exists. Warnings are always a lagging indicator.
  5. Know your transitive graph. You can't infer a dependency you don't know exists. Being able to answer the question "does arrayref appear anywhere in our builds and in what version?" in a few minutes is the difference between a scoped answer and a scrambled answer.

What this changes about your attack surface

For most teams, "our attack surface" still means the application: endpoints, authentication, and business logic that an attacker can reach from the outside. This is where exploitable bugs reside, and this is where testing should be rigorous. However, arrayref reminds us that the surface now extends backwards, to how the software is built, not just how it behaves after execution.

We think about security in the same way in both places: a discovery counts only after examining how the system actually behaves, not based on a version number or a scanner's guess. A crate isn't malicious because the feed says so; it's malicious because its build script does something the build script shouldn't. The same discipline that separates a real vulnerability from a false positive separates a real supply chain threat from log noise.

If you want this rigorous discipline to be applied to the part of the surface that an attacker can reach today, that is, the running application and its APIs, then that's exactly what Intrudify does: authenticated, context-aware tests that validate each discovery with a repeatable exploit before it reaches the pipeline. The pipeline side and the application side described above are two halves of the same mission: knowledge, along with evidence, of what an attacker can actually do.


Related reading: Navigating Supply Chain Security - Continuous Security Testing

Frequently asked questions

Was I affected by the arrayref compromise?

Only if your project or something it depends on downloaded and built one of the poisoned versions (arrayref 0.3.10, internment 0.8.7, or append-only-vec 0.1.9) within approximately 86 minutes of August 20, 2026, before they were deleted. Since crates are often downloaded transiently, check your lock files and CI logs instead of assuming you never used them.

Why did just building the project run the malware?

Rust build scripts (build.rs) are run on the machine performing the build. The malicious dependency used its build script to download and run the second-stage binary, so compiling any project that also depended on it in CI was sufficient to run the payload. There was no need to call any of the crate's functions.

The versions were removed in under 90 minutes. Isn't that fine?

The removal was fast, and it protected anyone who built after it. But a build-time payload harms every build that ran during the window, which matters most for automated pipelines that fetch fresh dependencies on each run. Measure your exposure against your build events, not against the disclosure timeline.

Is this a Rust-specific problem?

No. The same operators have run near-identical attacks against npm and PyPI. Any ecosystem that allows code to execute at install or build time shares the underlying weakness; only the syntax changes.

What's the single highest-value change we can make?

Commit your lockfiles and build with them enforced, so an unreviewed point release cannot enter a build automatically. It is the cheapest control that directly defeats the "poison a patch version" step this attack depends on.

Related posts
Supply Chain Beyond Your Walls: Navigating the Treacherous Waters of Supply Chain Security Compliance How to Prepare for a Security Audit Compliance SOC 2 vs ISO 27001: Which One Do You Actually Need?
Back to all posts