- Why investigating a Rust supply-chain story was not a whim
- The concern that started the investigation
- What happened in the ArrayRef incident
- The unexpected warning about investigating
- Action 1: Check Cargo’s local cache for the malicious crates
- Action 2: Install the RustSec dependency scanner
- Action 3: Audit the Burn project
- Action 4: Audit the Leptos project
- Action 5: Audit the GPUI project
- Action 6: Apply targeted fixes to Burn
- Action 7: Re-audit before compiling
- Action 8: Compile the exact audited dependency set
- The final compiler warning: important, but not a security incident
- Understanding every warning category
- What “safe” means after this investigation
- My Rust dependency-security routine from now on
- Reflection: why this was worth following through
- Sources
Why investigating a Rust supply-chain story was not a whim
Date: August 28, 2026
The concern that started the investigation
I had recently been installing and compiling Rust crates while learning Burn, Leptos, GPUI, Cargo utilities, and the wider Rust ecosystem. Then I watched Low Level’s video, “Would Rust have fixed this?”, about the August 2026 ArrayRef supply-chain attack.
The central lesson was uncomfortable but important:
Rust can prevent many accidental memory-safety errors, but it cannot make intentionally malicious code safe.
Rust’s ownership and type systems address problems such as invalid references, use-after-free errors, and data races in ordinary Rust code. They do not determine whether a package maintainer’s account has been compromised or whether a dependency deliberately downloads malware.
This incident exploited Cargo’s build process rather than a memory-safety flaw. A poisoned version of a trusted crate added a malicious dependency named proc-macro1, deliberately resembling the legitimate proc-macro2. The malicious code lived in a build.rs file. Cargo compiles and executes build scripts before compiling the rest of a package, so merely building or checking an affected dependency graph could trigger the payload.
That means commands as ordinary as these can cross an execution boundary:
cargo check
cargo build
cargo test
cargo run
cargo install
The danger was not that Rust malfunctioned. Cargo correctly executed code that an attacker had placed inside the trusted build chain.
What happened in the ArrayRef incident
On August 20, 2026, attackers published poisoned releases from what the Rust Security Response Team believes was a compromised maintainer account:
| Legitimate crate | Malicious version | Time available on crates.io |
|---|---|---|
arrayref | 0.3.10 | 86 minutes |
internment | 0.8.7 | 90 minutes |
append-only-vec | 0.1.9 | 107 minutes |
Those releases brought in the typosquatted proc-macro1 dependency. The Rust team also removed proc-macro-en, aovine, arone, aronenao, and tinymember as part of the response.
The incident was a supply-chain backdoor, not a confirmed self-propagating Rust worm. The video compared it with npm worms that steal package-publishing credentials and use them to poison additional packages automatically. The ArrayRef payload demonstrated the dangerous first half of that possibility—code execution through a trusted dependency—but public evidence did not show it automatically stealing Cargo publishing credentials and republishing more crates.
That distinction matters:
- Supply-chain attack: trusted software or its delivery path is poisoned.
- Backdoor/dropper: malicious code creates access or downloads another payload.
- Worm: malware automatically spreads from one compromised target to another.
The unexpected warning about investigating
While trying to understand the incident, ChatGPT displayed:
This content can’t be shown. We’re especially careful with cybersecurity requests.
The likely trigger was the combination of subjects being discussed: malware execution, command-and-control infrastructure, credential theft, persistence, and worm propagation. Those subjects can describe offensive activity, but they are also necessary for understanding how a public attack worked and how to defend against it.
My purpose was defensive and concrete:
- Determine whether my own Debian machine had downloaded the affected crates.
- Audit the Rust projects I had recently built.
- Understand the difference between malware, vulnerabilities, maintenance warnings, and compiler warnings.
- Apply safe updates where they were justified.
Ignoring the story simply because the investigation received a safety warning would have been the wrong lesson. The correct response was neither panic nor dismissal. It was verification.
Action 1: Check Cargo’s local cache for the malicious crates
The first action was the exact cache search recommended by the Rust Security Response Team:
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
The command returned directly to the prompt without printing a filename.
Meaning of the empty result
No known malicious crate archive from this campaign was present in Cargo’s default registry cache. Ordinary cargo clean removes a project’s build artifacts but does not normally erase this global registry cache, so the empty result was strong evidence that this machine had not downloaded the affected releases.
It was not a magical guarantee that every dependency on the computer was safe. It answered one specific question: Was there evidence of the known ArrayRef campaign in Cargo’s cache? The answer was no.
Action 2: Install the RustSec dependency scanner
The next question was broader: did any of my current Rust projects contain dependencies with known security advisories?
cargo audit was not installed:
error: no such command: `audit`
I installed the RustSec-maintained tool with its published lockfile:
cargo install cargo-audit --locked
I did not use sudo. Cargo build scripts run with the permissions of the account invoking Cargo, so Rust development and tool installation should not be performed as root.
The installation was verified:
cargo audit --version
Result:
cargo-audit-audit 0.22.2
cargo audit examines a project’s Cargo.lock against the RustSec Advisory Database. It identifies known vulnerabilities and can also report informational warnings such as unmaintained, unsound, or yanked packages.
Action 3: Audit the Burn project
The first scan examined the Burn demonstration project:
cargo audit --file ~/Projects/burn-demo/Cargo.lock
The lockfile contained 726 crate dependencies. This large number illustrates why checking only the few dependencies typed into Cargo.toml is insufficient: modern Rust projects often contain hundreds of transitive dependencies.
The initial findings were:
| Crate | Installed version | Classification | Meaning | Resolution |
h2 | 0.4.15 | Vulnerability | Unbounded empty HTTP/2 DATA frames could cause excessive memory use or a panic | Upgrade to >=0.4.16 |
stable-vec | 0.4.2 | Unsound | Panic-safety flaw could cause double-free/use-after-free in a narrow condition | Upgrade to >=0.4.3 |
chacha20 | 0.10.1 | Yanked | This release had been withdrawn from normal dependency selection | Upgrade to 0.10.2 |
bincode | 2.0.1 | Unmaintained | No longer actively maintained | Monitor upstream dependencies |
paste | 1.0.15 | Unmaintained | No longer actively maintained | Monitor upstream dependencies |
The audit ended with:
error: 1 vulnerability found!
warning: 4 allowed warnings found
This was not evidence that malware had executed. It meant one locked dependency had a published vulnerability, while four other packages carried advisory classifications that cargo audit treated as warnings.
Action 4: Audit the Leptos project
The Leptos project was scanned next:
cargo audit --file ~/Projects/leptos-demo/Cargo.lock
It contained 238 crate dependencies and reported:
paste 1.0.15— unmaintained.proc-macro-error2 2.0.1— unmaintained.
The scan found zero vulnerabilities. These warnings should be watched, but they are primarily matters for the upstream projects that currently depend on those packages.
Action 5: Audit the GPUI project
The GPUI project was also scanned:
cargo audit --file ~/Projects/gpui-demo/Cargo.lock
It contained 699 crate dependencies and reported:
paste 1.0.15— unmaintained.rustybuzz 0.20.1— unmaintained.ttf-parser 0.25.1— unmaintained.
Again, the scan found zero vulnerabilities. Because these are transitive dependencies in the GPUI/Zed stack, forcing replacements locally could create incompatibilities. The proper action for a learning project is to monitor upstream updates rather than invent unsupported substitutions.
Action 6: Apply targeted fixes to Burn
I avoided a blanket cargo update, which could have changed dozens or hundreds of unrelated packages. Instead, each confirmed finding was addressed with a precise patch update.
Patch the h2 vulnerability
cd ~/Projects/burn-demo
cargo update -p h2 --precise 0.4.16
Cargo reported:
Updating h2 v0.4.15 -> v0.4.16
Patch the stable-vec soundness problem
cargo update -p stable-vec --precise 0.4.3
Cargo reported:
Updating stable-vec v0.4.2 -> v0.4.3
Replace the yanked chacha20 release
cargo update -p chacha20 --precise 0.10.2
Cargo reported:
Updating chacha20 v0.10.1 -> v0.10.2
Each command altered the locked version of only the named package. Cargo explicitly noted that the unrelated dependencies remained unchanged.
Action 7: Re-audit before compiling
The updated Burn lockfile was scanned again:
cargo audit
The vulnerability, unsoundness, and yanked-release findings were gone. Only two allowed maintenance warnings remained:
bincode 2.0.1— unmaintained.paste 1.0.15— unmaintained.
There was no error: vulnerability found line. At this point, Burn’s locked dependency graph contained no vulnerabilities known to RustSec.
Action 8: Compile the exact audited dependency set
The final verification used:
cargo check --locked
The --locked option told Cargo to use the exact versions already recorded in Cargo.lock and fail rather than silently calculate a different dependency set.
Cargo downloaded the three selected patched crates:
Downloaded chacha20 v0.10.2
Downloaded h2 v0.4.16
Downloaded stable-vec v0.4.3
The complete Burn dependency graph compiled successfully:
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 20s
The build log also contained this legitimate crate:
Compiling proc-macro2 v1.0.107
That name deserves deliberate attention. proc-macro2 is the legitimate crate. The malicious typosquat from the ArrayRef incident was proc-macro1. The similar name and matching-looking version were part of what made the attack deceptive.
The final compiler warning: important, but not a security incident
After the successful check, Cargo reported that these packages contain code that a future Rust compiler will reject:
burn-cubecl 0.21.0burn-cubecl-fusion 0.21.0
I inspected the details:
cargo report future-incompatibilities --id 1
The warning concerns a trailing semicolon produced by the local_tuner!() macro in expression position. Rust accepts this behavior today but is phasing it out. In a future release, it will become a compilation error.
This warning does not indicate:
- malware;
- a currently exploitable vulnerability;
- a failure of today’s build;
- a problem in my own
main.rs.
It means Burn’s maintainers will need to adjust macro code for a future Rust compiler. Pre-release versions 0.22.0-pre.1 and 0.22.0-pre.2 were available, but jumping to a pre-release solely to silence the warning would introduce unnecessary instability. The prudent action is to remain on the working stable 0.21.0 release and revisit the issue when Burn publishes its next stable version.
Understanding every warning category
Today’s investigation showed why security terminology must be interpreted carefully:
| Classification | What it means | What I should do |
| Malicious | Code intentionally performs harmful behavior | Stop, isolate, investigate exposure, and follow incident-response guidance |
| Vulnerable | A known security flaw exists in otherwise legitimate code | Upgrade to a patched version and test |
| Unsound | Safe Rust APIs may permit memory-unsafe behavior under documented conditions | Prefer a patched version even when the advisory is informational |
| Yanked | The publisher removed a release from normal new dependency selection | Investigate why; do not automatically assume malware |
| Unmaintained | Active maintenance has stopped | Monitor upstream replacements and avoid adopting it directly in new work |
| Future-incompatible | Current code will become invalid under a future compiler rule | Continue safely today; plan an upstream upgrade before the rule becomes an error |
These labels are not interchangeable. A yanked package is not necessarily malicious. An unmaintained package is not automatically vulnerable. A future compiler warning is not evidence of compromise. A clean build is also not proof that every dependency is trustworthy.
What “safe” means after this investigation
No single command can mathematically prove that a development computer is completely safe. What I now have is a collection of independent, mutually reinforcing evidence:
- The official ArrayRef cache search found none of the malicious releases.
- RustSec scans found no ArrayRef campaign advisories in any of the three project lockfiles.
- The only actual Burn vulnerability was identified and patched.
- The
stable-vecsoundness issue was patched. - The yanked
chacha20version was replaced. - A second audit found zero known vulnerabilities.
cargo check --lockedsuccessfully compiled the precise audited dependency set.- The remaining messages were classified and understood rather than ignored.
The responsible conclusion is not “nothing bad can ever happen.” It is:
My Rust projects show no evidence of the ArrayRef compromise, and their current locked dependencies contain no vulnerabilities known to RustSec as of this audit.
That is a defensible conclusion grounded in evidence—not a feeling and not a whim.
My Rust dependency-security routine from now on
Before adding a direct dependency
For an unfamiliar crate, I will first examine its metadata, repository, maintenance activity, release history, and purpose:
cargo info crate-name
I do not need to manually audit hundreds of transitive crates before every experiment, but I should understand the direct dependency I am choosing and be cautious with brand-new, obscure, or unexpectedly complex packages.
After adding a dependency, but before the first build
cargo add crate-name
git diff -- Cargo.toml Cargo.lock
cargo tree
cargo audit
cargo add records and resolves the dependency. The later compile or check is the point at which build scripts may execute, so reviewing and auditing the lockfile first is meaningful.
Build the audited versions
cargo check --locked
For an application or executable project, I will keep Cargo.lock under version control. It is the receipt showing the exact dependency set I audited and compiled.
Install Cargo tools reproducibly
cargo install tool-name --locked
I will never run Cargo installation or builds through sudo.
Audit regularly
I will run:
cargo audit
at these times:
- after adding or substantially updating dependencies;
- before returning to an older Rust project;
- before publishing or deploying a project;
- periodically while a project remains active;
- after hearing about a credible Rust ecosystem incident.
Investigate dependency paths
When an advisory names a transitive crate, I can discover why it is present:
cargo tree -i crate-name
This tells me which higher-level dependency brought it into the project. I can then decide whether a precise patch update is sufficient or whether an upstream library must be upgraded.
Patch narrowly, then verify
When RustSec identifies a patched version and the dependency requirements permit it:
cargo update -p crate-name --precise patched-version
cargo audit
cargo check --locked
I will avoid broad, reflexive updates when a targeted patch is available.
Treat yanked warnings as questions, not commands
The ArrayRef attackers reportedly yanked clean releases to make an update appear urgent. Therefore, a yanked warning should prompt investigation—not an automatic rush to the newest version.
For nonurgent releases, allowing time for maintainers, automated scanners, and the community to examine a fresh package can reduce exposure to a short-lived poisoned release.
Use isolation for higher-risk experiments
For a new, obscure, or suspicious crate, I can use one of my disposable virtual machines. That environment should not contain personal browser profiles, SSH keys, publishing credentials, password-manager sessions, or other secrets.
Isolation is especially useful when experimenting with a package that contains an unexpected build script or network-related build dependency.
Let upstream maintainers handle transitive replacements
I will monitor the remaining unmaintained dependencies:
- Burn:
bincode,paste. - Leptos:
paste,proc-macro-error2. - GPUI:
paste,rustybuzz,ttf-parser.
I will not force random replacements into a dependency graph that I do not maintain. When Burn, Leptos, or GPUI publishes a compatible stable update, I can update the top-level framework, re-audit, and rebuild.
Watch Burn’s future compiler compatibility
I will remain on Burn 0.21.0 while it is the working stable release. When the next stable Burn version becomes available, I should review its release notes, update deliberately, run cargo audit, and repeat cargo check --locked.
Reflection: why this was worth following through
The original fear—an ArrayRef compromise on my Debian computer—was not confirmed. That does not make the investigation unnecessary. The process found and resolved three real dependency concerns that would otherwise have remained in my Burn lockfile.
Had I ignored the video, I would not necessarily have been infected. But I would still have missed:
- a published HTTP/2 vulnerability;
- a patched Rust soundness problem;
- a yanked cryptography dependency;
- several maintenance warnings worth monitoring;
- a future Rust compatibility issue in Burn’s GPU stack.
The lesson is not to react fearfully to every security headline. The lesson is to develop a repeatable method:
Hear the warning. Identify the exact claim. Check the official advisory. Inspect the local evidence. Patch only what is confirmed. Re-audit. Rebuild. Record what was learned.
That is how curiosity becomes security practice.
Sources
- Rust Security Response Team: Supply chain attack on arrayref
- The Cargo Book: Build Scripts
- RustSec: cargo-audit
- RUSTSEC-2026-0258: h2 unbounded empty DATA frames
- RUSTSEC-2026-0267: stable-vec panic-safety unsoundness
- Low Level: Would Rust have fixed this?