
TL;DR
On August 20, 2026, compromised arrayref 0.3.10 pulled in a proc-macro1 typosquat whose build script fetched a remote binary. Coding agents that cargo update on yank warnings walk into this.
Last updated: August 21, 2026
| Source | Description |
|---|---|
| SafeDep incident writeup | Technical analysis and IOCs (fetched August 21, 2026) |
| Rust Blog: Supply chain attack on arrayref | Official timeline, deleted versions, cache check |
| RUSTSEC-2026-0260 | Advisory for arrayref 0.3.10 |
| RustSec advisory-db#3161 | Reporter writeup: yank lure, payload host, hashes |
| Hacker News discussion | 533 points, 480 comments as of August 21, 2026 |
On August 20, 2026, a compromised release of arrayref appeared on crates.io. Version 0.3.10 added a first-ever dependency on proc-macro1, a typosquat of the real proc-macro2. The typosquat's build script downloaded and ran a remote binary while the project compiled. You did not have to call a macro or ship a binary. cargo build was enough. crates.io removed the malicious versions. RustSec published RUSTSEC-2026-0260 and sibling advisories for the rest of the cluster.
The part that matters on this site is how a coding agent would have behaved in the 86-minute window. Agents run cargo add and cargo update. They treat a yank warning as a failing check. They do not always read the Cargo.toml diff. That is the same class of mistake as treating agent config files as scaffolding instead of executable supply chain.
The genuine arrayref, internment, and append-only-vec crates are maintained by droundy. The Rust security-response post says the team does not believe that author was acting maliciously. Their crates.io account was likely compromised and has been locked. github.com/droundy now 404s.
A separate account, dtolney, published proc-macro1. The username is one letter off David Tolnay's real dtolnay account. Metadata forged an author line and a dtolnay/proc-macro1 repository that also 404s.
| Crate | Version | Publisher | Status |
|---|---|---|---|
arrayref | 0.3.10 | droundy (compromised) | Malicious, removed |
internment | 0.8.7 | droundy (compromised) | Malicious, removed |
append-only-vec | 0.1.9 | droundy (compromised) | Malicious, removed |
proc-macro1 | all versions | dtolney (impersonation) | Typosquat, crate removed |
proc-macro-en, aovine, arone, aronenao, tinymember | all versions | Malicious deps, removed |
proc-macro1 is not proc-macro2. Its src/ was a renamed copy of the real token crate, so the build kept succeeding while the build script ran.
The reporter who filed advisory-db#3161 gave the timing: proc-macro1 1.0.107 at 07:11 UTC, arrayref 0.3.10 at 07:15 UTC. Version 1.0.106 of proc-macro1, published about five hours earlier, was a clean staging copy of proc-macro2. arrayref 0.3.9 and below are clean.
How long each compromised parent crate stayed up:
arrayref@0.3.10: published 07:15:00Z, deleted 08:41:40Z. Online 86 minutes.internment@0.8.7: published 07:34:07Z, deleted 09:04:11Z. Online 90 minutes.append-only-vec@0.1.9: published 07:37:49Z, deleted 09:25:24Z. Online 107 minutes.RUSTSEC-2026-0260 adds a download count: 0.3.10 was downloaded 2,285 times, under 10% of arrayref traffic, because most users already had an older version in a lockfile.
The owner account yanked arrayref 0.3.5 through 0.3.9. Per cargo yank, yanked versions stay downloadable for existing lockfiles and stop being selected for new resolution. Cargo then warns you to consider updating to a version that is not yanked. During the window, the only non-yanked release was 0.3.10. The reporter said that warning is how they hit it. The response team deleted 0.3.10 and unyanked the clean versions. Deletion matters: a yanked crate can still be fetched by a lockfile that already points at it. A deleted crate cannot.
arrayref is a four-macro crate with about 245 million all-time downloads. It sits transitively under tiny-skia, sctk-adwaita, and winit, which puts it under GUI work on egui, eframe, and iced. Those numbers measure how widely the crate is used, not a count of infected builds.
From the archive
Aug 21, 2026 • 7 min read
Aug 21, 2026 • 10 min read
Aug 15, 2026 • 7 min read
Aug 15, 2026 • 10 min read
The payload did not need a runtime call. Cargo builds every declared non-optional dependency whether or not your code uses it. arrayref 0.3.10 kept the ordinary macro source, set build = false on itself, and added one manifest line: a dependency on proc-macro1 1.0.107. That was sufficient. The malicious work happened in proc-macro1's build.rs.
A coding agent that sees "consider updating to a version that is not yanked", runs cargo update, and does not pause on a lockfile diff that introduces proc-macro1 has just applied the lure. The same agent that runs cargo add without reading the manifest will miss a new build-dependencies block of ureq, rustls, and base64 on a crate that claims to be a token parser. That combination is the smell.
This is the crate-ecosystem version of Claude Code plugin URLs: the install path is the trust boundary. The checklist before connecting tools starts with what the agent can write and call, not with whether the model is careful. An agent with cargo on its PATH can write a lockfile and compile it. That includes OpenCode and Claude Code sessions. Compilation is code execution. If that compile happens inside a sandbox with network, a build script that fetches a binary still has a place to phone home.
1. Pin, and keep the lockfile in review.
Commit Cargo.lock for any repo an agent is allowed to build. Do not let an agent run cargo update unattended. If a crate must be extra-pinned, use an exact requirement (arrayref = "=0.3.9"). RUSTSEC-2026-0260 lists <=0.3.9 as unaffected. The 2,285 downloads of 0.3.10 are the set that refreshed.
2. Run cargo audit and cargo deny check advisories in CI, on the committed lockfile.
cargo install cargo-audit
cargo install --locked cargo-deny
cargo audit
cargo deny check advisories
cargo audit is the RustSec subcommand that reads Cargo.lock. cargo deny check advisories is the Embark check against the same database, now including RUSTSEC-2026-0260 through RUSTSEC-2026-0266. GitHub's malware-advisory importer covers crates.io too (eight ecosystems). These gates fail the build when an advisory exists. They cannot warn you about a crate published 12 minutes ago.
3. Do not auto-apply yank warnings.
A yank warning is a review event. This incident used yank as delivery: older clean versions were yanked so Cargo would point at the new bad one. An agent instruction of the form "if Cargo warns about a yanked crate, update it" is how you walk into that. If cargo deny is configured with yanked = "deny" or "warn", keep that as an alert. Do not wire it to an autonomous cargo update.
4. Review new build-dependencies, especially on token crates.
Any agent commit or lockfile refresh that adds a crate whose name is one character off a famous crate (proc-macro1 vs proc-macro2, dtolney vs dtolnay), a first-ever dependency on a crate that previously had none, or build-dependencies of ureq / reqwest, rustls / native-tls, or base64, needs a human. Cargo will compile that dependency even if no Rust source imports it. The review question is "why does this crate grow a network stack at compile time."
Contract: agents may propose Cargo.toml and Cargo.lock changes. They may not apply yank-driven updates or add build-dependencies without a receipt that names the crate, the new deps, and why a compile-time HTTP client is required.
The Rust team published a cache check. Run it on developer laptops and CI images that built Rust during the window:
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
Also search project lockfiles for arrayref 0.3.10, internment 0.8.7, append-only-vec 0.1.9, or any proc-macro1 entry. If those versions resolved and the project was compiled, assume the build script ran on that host.
SafeDep's published indicators of compromise, for detection only:
| Type | Indicator | Detail |
|---|---|---|
| Network | 23.254.165.112:9089 | Payload host (HTTPS) |
| Network | 23.254.165.112:443 | C2, passed to the payload as an argument |
| File (Unix) | /tmp/rust-setup | Downloaded executable |
| File (Windows) | %TEMP%\rust-setup.ps1 | Downloaded PowerShell script |
| File (Windows) | %TEMP%\rust-setup-launch.vbs | VBScript launcher |
| Artifact | SHA256 25ad700976873c76af785cb99b33c48db7df8b81f21d1e9e06b3676b9a9373ae | arrayref 0.3.10 crate |
The TLS client accepted any certificate. Treat that as an IOC, not as something to reproduce.
If you compiled a malicious version, treat the host as compromised, rotate credentials that were reachable from that environment, and follow your incident process. Do not clean the crate cache and keep working. The build script's job was to leave the compiler and keep running.
Lockfiles saved most builds. The failure mode that remains is autonomous resolution: an agent that treats yank warnings, cargo update, and "add whatever makes the build green" as chores. Build scripts are executable supply chain. So are the diffs that introduce them.
Yes. RUSTSEC-2026-0260 classifies it as malicious. Version 0.3.10 depended on proc-macro1, whose build script ran a remote binary at compile time. crates.io removed 0.3.10 after about 86 minutes. Versions <=0.3.9 are unaffected.
Search Cargo.lock for arrayref 0.3.10, internment 0.8.7, append-only-vec 0.1.9, or any proc-macro1 entry. Run the find command from the Rust security-response post against ~/.cargo/registry/cache.
proc-macro2 is the legitimate token crate. proc-macro1 was a typosquat published by dtolney impersonating dtolnay. Its library source was a renamed copy of proc-macro2, so builds still succeeded. The malicious behavior was in the build script.
No. Yanking the clean 0.3.5 through 0.3.9 releases was the lure that pointed Cargo at 0.3.10. A yank warning is a review event. Do not encode "update to the non-yanked version" as an agent default.
Yes, as a transitive dependency. SafeDep notes the path through tiny-skia, sctk-adwaita, and winit into egui, eframe, and iced. Check the lockfile, not your direct dependencies.
Some links to tools above are referral links - see our affiliate disclosure.
Read next
A Hacker News thread on config files that run code points at the next AI coding risk: agent hooks, skills, and editor rules need review like executable dependencies.
8 min readDependabot's malware detection expands from npm to PyPI, Maven, RubyGems, NuGet, Go, crates.io, and PHP Composer by ingesting OpenSSF's malicious-packages data into the GitHub Advisory Database.
6 min readBefore an AI agent gets tools, files, APIs, MCP servers, or deployment access, decide what it can read, write, call, log, and roll back.
8 min readTechnical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.
Open-source terminal agent runtime with approval modes, rollback snapshots, MCP servers, LSP diagnostics, and a headless...
View ToolAI app builder - describe what you want, get a deployed full-stack app with React, Supabase, and auth. No coding requi...
View ToolStackBlitz's in-browser AI app builder. Full-stack apps from a prompt - runs Node.js, installs packages, and deploys....
View ToolHigh-performance code editor built in Rust with native AI integration. Sub-millisecond input latency. Built-in assistant...
View ToolReal-time prompt loop with history, completions, and multiline input.
Claude CodeWhat MCP servers are, how they work, and how to build your own in 5 minutes.
AI AgentsA complete, citation-backed Claude Code course with setup, prompting systems, MCP, CI, security, cost controls, and capstone workflows.
ai-development
A Hacker News thread on config files that run code points at the next AI coding risk: agent hooks, skills, and editor ru...

Dependabot's malware detection expands from npm to PyPI, Maven, RubyGems, NuGet, Go, crates.io, and PHP Composer by inge...

Before an AI agent gets tools, files, APIs, MCP servers, or deployment access, decide what it can read, write, call, log...

Claude Code's newer plugin URL and hard-deny controls are small release-note items with a big implication: agent extensi...

AI agents are getting their own computers. Here is how to choose a sandbox architecture: filesystem isolation, network p...

A ripgrep musl binary crashing during very-large searches turned out to be a suspected Linux 7.0 kernel race - a thread'...

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.