Dependency Security

Rust Cargo Dependency Security Guide

How to secure your Rust supply chain with Cargo.lock, crate auditing, and build script controls.

Bob
Security Researcher
5 min read

Rust's safety guarantees stop at the language level. Your Cargo.toml pulls in third-party code that can do anything the operating system allows, including crates with unsafe blocks, build scripts that execute arbitrary commands, and procedural macros that run at compile time. Here is how to secure your Rust dependency chain.

Rust's Dependency Landscape

crates.io is the primary package registry for Rust. It is smaller than npm or PyPI but growing fast. The Rust ecosystem has some inherent security advantages: memory safety reduces the vulnerability surface of well-written crates, and the compiler catches many classes of bugs at compile time.

But supply chain risks remain:

  • Build scripts (build.rs). These execute arbitrary code during compilation. A malicious build.rs can exfiltrate data, modify source files, or install backdoors.
  • Procedural macros. Proc macros run at compile time with full system access. They are essentially plugins for the Rust compiler.
  • Unsafe code. Crates with unsafe blocks bypass Rust's safety guarantees. A bug in unsafe code can be exploited just like a C vulnerability.
  • Typosquatting. crates.io has namespace squatting protections, but typosquatting is still possible.

Cargo.lock: Your Security Baseline

Cargo.lock records exact versions and checksums for every dependency:

[[package]]
name = "serde"
version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91d7d1ac55e4903dab..."

For applications: Always commit Cargo.lock. This ensures reproducible builds and prevents silent dependency updates.

For libraries: Committing Cargo.lock is optional (consumers use their own lockfile), but it is useful for reproducible CI builds of the library itself.

cargo-audit

cargo-audit checks your dependency tree against the RustSec Advisory Database:

cargo install cargo-audit
cargo audit

Run this in CI and fail builds on any advisory:

cargo audit --deny warnings

cargo-audit also supports checking for yanked crates and unsound code:

cargo audit --deny yanked --deny unsound

Yanked crates are versions that the author has marked as broken or insecure. Depending on a yanked crate is a signal that your dependencies are stale.

cargo-vet: Supply Chain Verification

cargo-vet is a more thorough tool developed by Mozilla. It tracks which crates have been reviewed and by whom:

cargo install cargo-vet
cargo vet init

After initialization, cargo vet fails if any dependency has not been audited. You can mark crates as reviewed:

cargo vet certify serde 1.0.190

The real power of cargo-vet is audit sharing. You can import audit results from trusted organizations:

# supply-chain/config.toml
[imports.mozilla]
url = "https://raw.githubusercontent.com/nickel-org/nickel.rs/main/supply-chain/audits.toml"

This creates a web of trust where organizations collectively audit the crate ecosystem.

cargo-deny

cargo-deny enforces policies on your dependency tree:

cargo install cargo-deny
cargo deny init
cargo deny check

Configure it in deny.toml:

[bans]
multiple-versions = "deny"
wildcards = "deny"

[sources]
unknown-registry = "deny"
unknown-git = "deny"

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

[advisories]
db-path = "~/.cargo/advisory-db"
vulnerability = "deny"
unmaintained = "warn"
yanked = "deny"

This single configuration file blocks:

  • Dependencies from unknown registries
  • Git dependencies from unknown sources
  • Crates with disallowed licenses
  • Crates with known vulnerabilities
  • Yanked crate versions
  • Multiple versions of the same crate (which bloats binaries and increases audit burden)

Controlling Build Scripts

Build scripts are the highest-risk component of the Rust supply chain. A build.rs file runs on your machine during compilation with your user's full permissions.

Audit build scripts explicitly. When adding a new dependency, check if it has a build.rs:

# List all dependencies with build scripts
cargo metadata --format-version=1 | jq '.packages[] | select(.has_build_script) | .name'

Sandbox your builds. Consider running cargo build inside a container with limited network access and filesystem permissions. In CI, this is straightforward:

build:
  runs-on: ubuntu-latest
  container:
    image: rust:1.73
    options: --network=none

Disabling network access during builds prevents build scripts from phoning home.

Procedural Macro Security

Proc macros deserve special scrutiny because they execute arbitrary code at compile time. Popular proc macros like serde_derive and thiserror are well-audited, but lesser-known proc macros should be reviewed carefully.

When evaluating a proc macro crate:

  1. Check the source code of the proc macro itself.
  2. Look for network calls, filesystem operations, or environment variable access.
  3. Prefer proc macros from well-known maintainers with multiple contributors.

Minimizing Unsafe Code

Use cargo-geiger to measure the amount of unsafe code in your dependency tree:

cargo install cargo-geiger
cargo geiger

This produces a report showing unsafe usage in each crate. Prefer dependencies with zero or minimal unsafe code. When unsafe code is necessary, ensure it is well-documented and tested with tools like Miri.

SBOM Generation

Generate a CycloneDX SBOM for your Rust project:

cargo install cargo-cyclonedx
cargo cyclonedx --format json

This produces an SBOM that captures your complete dependency tree with versions, hashes, and license information.

How Safeguard.sh Helps

Safeguard.sh provides continuous monitoring for your Rust supply chain. It ingests CycloneDX SBOMs from your Cargo builds, correlates dependencies against the RustSec database and other vulnerability feeds, and gives you organization-wide visibility into which crates are deployed where. When a new advisory drops in RustSec, Safeguard.sh tells you exactly which services are affected and helps prioritize remediation based on severity and exposure.

Never miss an update

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