by datastudy.nl

Field notes for teams tracking critical CVEs and major incidents

Engineering

Rust supply chain attack targets build-time code in crates

A compromised crates.io maintainer account pushed malicious versions of arrayref, internment, and append-only-vec, with a build script that downloaded payloads during compilation. Here is how to check your lockfile and secure CI.

Bar chart of three affected Rust crates by total downloads: arrayref at approximately 120 million, internment at approximately 80 million, and append-only-vec at approximately 45 million, based on crates.io download counts at the time of the 2026-08-20 supply chain attack.
Approximate crates.io download counts for the three affected crates at the time of the August 20, 2026 supply chain attack. Source: crates.io. Data Today benchmark.

On August 20, 2026, a maintainer's credentials for several popular Rust crates were compromised, and the attacker used that access to publish malicious new versions of arrayref, internment, and append-only-vec. Each malicious version pulled in a typosquatted dependency called proc-macro1, whose build script downloaded and ran a remote payload the moment a developer or CI runner executed cargo build. The Rust Security Response Team confirmed the compromise and removed the malicious versions from crates.io within roughly 90 minutes of publication, but anyone who pulled those versions in that window is at risk. This is a classic Rust supply chain attack: build-time malware execution via a compromised maintainer account on high-traffic crates, and it underscores why build.rs is a critical security boundary.

The malicious versions were live on crates.io for under two hours, but any build that pulled them during that window executed the payload.

The attack is a textbook example of how build.rs execution turns a compromised maintainer account into direct code execution on every machine that compiles the crate. As the Rust Security Response Team explained, the attacker hijacked the account of the maintainer of arrayref, a crate with over 120 million downloads, and used it to republish the crate with a new dependency on the typosquatted proc-macro1. The team also found that internment and append-only-vec, owned by the same maintainer, had received similar treatment. The team does not believe the maintainer acted maliciously, but suspects their computer or credentials were compromised.

Bar chart of three affected Rust crates by total downloads: arrayref at approximately 120 million, internment at approximately 80 million, and append-only-vec at approximately 45 million.
Approximate crates.io download counts for the three affected crates at the time of the August 20, 2026 supply chain attack. Source: crates.io. Data Today benchmark.

The attacker published the three malicious versions between 07:15 and 07:37 UTC on August 20. The Rust Security Response Team deleted them between 08:41 and 09:25 UTC, meaning each was available for between 86 and 107 minutes. The window was short, but the target was not: arrayref alone has roughly 120 million lifetime downloads on crates.io. The attacker chose a crate with enormous reach, and the payload delivered through build.rs ran with the full privileges of the user or CI runner that invoked cargo build.

How does this Rust supply chain attack work?

The attack chain is simple and effective. First, the attacker compromises the maintainer's GitHub account. Because crates.io delegates authentication entirely to GitHub OAuth, there is no separate password database to breach: a phished GitHub credential or a stolen session cookie is all it takes to inherit the maintainer's publish rights. Once inside, the attacker publishes a new, malicious version of a trusted crate. That version adds a dependency on a typosquatted crate, in this case proc-macro1, which mimics the legitimate proc-macro. The typosquatted crate contains a build.rs script that downloads and executes a remote payload during compilation.

The build.rs vector is what makes Rust supply chain attacks particularly dangerous. Unlike many package managers, Cargo executes a crate's build script as native code on the building machine before compilation even starts, with no sandboxing by default. A malicious crate version does not need to wait for a vulnerable code path to be called in production. It runs immediately, with whatever privileges the build process has. That means any developer running cargo build on a coffee shop network, or any CI runner with cloud credentials in its environment, is a potential target.

The broader pattern here is not unique to Rust. The npm ecosystem has seen identical attacks, from the event-stream compromise in 2018 to ua-parser-js in 2021. What makes Rust different is the build.rs execution model, which gives a compromised crate near-immediate code execution on the build host. As a detailed case study on crates.io account takeovers notes, the authentication model that links crates.io to GitHub OAuth means that securing a crates.io account is, in practice, securing a GitHub account. The same post also documents the earlier rustdecimal typosquat incident, which showed that crates.io would accept and distribute a crate carrying live malware via build.rs, a fact this week's attack confirms.

The targeting of .env files is another parallel. In March 2026, five malicious Rust crates were found exfiltrating .env files from CI/CD pipelines, aiming to steal API keys, tokens, and cloud credentials. The arrayref attack follows the same logic: the build host is a high-value target because it holds the keys to deployment.

What should I do if I run Rust in production?

If you run Rust in production, the immediate task is to check whether any of the malicious versions made it into your dependency tree. The Rust Security Response Team published a find command to scan ~/.cargo/registry/cache for the affected crate archives. Here it is:

find ~/.cargo/registry/cache -type f \( \
-name 'append-only-vec-0.1.9.crate' -o \
-name 'arrayref-0.3.10.crate' -o \
-name 'internment-0.8.7.crate' -o \
-name 'proc-macro1-*.crate' -o \
-name 'proc-macro-en-*.crate' -o \
-name 'aovine-*.crate' -o \
-name 'arone-*.crate' -o \
-name 'aronenao-*.crate' -o \
-name 'tinymember-*.crate' \
\) -print

If that command returns any results, you have a problem. Assume the payload ran, assume credentials were exfiltrated, and rotate any secrets that were accessible to the build environment during the affected window. That includes cloud provider credentials, database passwords, API keys, and any registry tokens. Audit CI/CD jobs that ran with publish or deploy credentials during the window. The Rust Security Response Team's incident notice is the authoritative source for the list of malicious versions and the scan command.

Beyond the immediate scan, the attack highlights three concrete steps every Rust shop should take now.

  • Pin your dependencies with Cargo.lock and commit it. A floating dependency range is an open door to whatever version gets published next, malicious or not. This applies to libraries too, where committing a lockfile is sometimes skipped. The lockfile is your bill of materials. Commit it.
  • Run cargo audit and cargo deny in CI. Both tools check against the RustSec Advisory Database and can catch known-malicious or known-vulnerable crate versions before they reach a build. Wire them into your CI pipeline as a required check.
  • Restrict build-time network egress in CI. A malicious build.rs has nowhere to phone home if the build runner cannot reach the internet. Egress filtering is the single most effective control against build-time malware, and it is cheap to implement.

For an example of how build-time malware can chain into deeper compromise, see our earlier coverage of AI coding agent malware that hides in clean GitHub repos.

How do I secure my crates.io maintainer account?

If you publish crates, the attack surface is your GitHub account. Crates.io authentication is GitHub OAuth only, so GitHub account security is crates.io account security. Enable hardware-key or app-based two-factor authentication on your GitHub account, and audit active sessions and OAuth app grants regularly. Remove former collaborators and unused CI-service accounts from your crate's owner list.

Move to scoped, short-lived crates.io API tokens. Before scoped tokens were introduced, a single leaked token could publish or yank any crate the account owned, with no expiration. Replace any old unscoped tokens with scoped tokens limited to the specific crate and action needed, and rotate them on a schedule. Where available, adopt trusted publishing from CI so no long-lived secret sits in a repository or pipeline at all. Never let tokens land in logs, environment dumps, or public repositories. Treat a crates.io token with the same discipline as a cloud provider credential.

The arrayref incident also shows that the crates.io team can respond quickly, but it cannot undo builds that already ran. The malicious versions were online for under two hours, and the team removed them, unyanked the maliciously yanked legitimate versions, and locked the compromised account. That response is strong, but it is reactive. The defender's advantage in supply chain security is that you control your build environment. You decide what runs, what reaches the internet, and what credentials are present.

What other Cargo vulnerabilities should I watch?

The arrayref attack is not the only recent Cargo vulnerability. In a separate issue, Cargo was found to incorrectly handle symlinks inside crate tarballs downloaded from third-party registries, allowing a malicious crate to override the source code of another crate from the same registry. The vulnerability is tracked as CVE-2026-5223 and affects only users of third-party registries, not crates.io users, since crates.io forbids uploading crates containing symlinks. Rust 1.96.0, released on May 28, 2026, updates Cargo to reject extracting any symlink within crate tarballs, regardless of registry. If you use a third-party registry and have not upgraded to Rust 1.96.0 or later, audit your registry for the presence of symlinks and configure it to reject them if possible.

The payoff for tightening build security

Supply chain attacks exploit trust. A compromised maintainer account on a crate with 120 million downloads is a defender's nightmare because the trust is already established: the crate is widely used, the maintainer is known, and the new version looks like any other release. The arrayref attack shows that the Rust ecosystem is not immune to the same account-takeover patterns that have hit npm and PyPI. The difference is that build.rs execution makes the blast radius wider: the payload runs on your machine, with your privileges, the moment you build. Tightening build security is not a one-off response to this incident. It is the ongoing cost of relying on a public package registry. Pin your lockfile, audit your dependencies, restrict build-time egress, and treat your publish credentials like cloud root. The trust you are protecting is not just yours. It belongs to every downstream user who runs cargo build on your code.

Sources