Dependency Auditing
Modern software projects frequently pull in dozens or hundreds of transitive crates. Dependency auditing inspects Cargo.lock and crate source code to detect known security vulnerabilities (CVEs and RustSec advisories), unmaintained or yanked crates, incompatible open-source licenses, and untrusted third-party build scripts.
Cargo.toml + Cargo.lock
|
+----------------------+----------------------+
| | |
v v v
[ cargo-audit ] [ cargo-deny ] [ cargo-vet ]
Checks Cargo.lock Enforces policies: Verifies peer-reviewed
against RustSec - Advisories supply-chain audits for
Advisory Database - License allowlist every crate version &
(CVEs, yanked, - Banned crates diff (`supply-chain/`)
unmaintained) - Duplicate versions
Auditing Tools in the Rust Ecosystem
| Tool | Install Command | Primary Focus |
|---|---|---|
cargo-audit |
cargo install cargo-audit --locked |
Scans Cargo.lock against the RustSec Advisory Database for memory-safety bugs, CVEs, unmaintained crates, and yanked versions. |
cargo-deny |
cargo install cargo-deny --locked |
All-in-one CI linter (deny.toml) checking security advisories, SPDX license compliance, banned dependencies, duplicate crate versions, and allowed registry sources. |
cargo-vet |
cargo install cargo-vet --locked |
Supply-chain verification tool that ensures every third-party crate version in Cargo.lock has been audited by your team or a trusted organization. |
Scanning for Security Advisories with cargo audit
Running cargo audit compares every package and version in Cargo.lock against the RustSec database:
cargo audit --deny warnings
Fetching advisory database from `https://github.com/RustSec/advisory-db.git`
Loaded 745 security advisories (from /Users/dev/.cargo/advisory-db)
Scanning Cargo.lock for vulnerabilities (42 crate dependencies)
Policy Enforcement with cargo-deny (deny.toml)
A deny.toml file at the root of a repository enforces four automated gates via cargo deny check:
# File: deny.toml
[advisories]
unmaintained = "workspace"
yanked = "deny"
[licenses]
# Only allow permissive open-source licenses in the dependency graph
allow = [
"MIT",
"Apache-2.0",
"Unicode-3.0",
"BSD-3-Clause",
]
[bans]
# Warn when two major versions of the same crate are pulled into the build
multiple-versions = "warn"
# Forbid OpenSSL to ensure pure-Rust `rustls` is used everywhere
deny = [
{ name = "openssl-sys" },
]
[sources]
unknown-registry = "deny"
unknown-git = "deny"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
Inspecting cargo metadata Programmatically
Under the hood, auditing tools inspect the resolved dependency graph by running cargo metadata --format-version 1, which outputs machine-readable JSON describing every package, license, target, and resolved feature in the workspace:
#[derive(Debug)]
struct CrateLicenseCheck {
name: &'static str,
spdx_expr: &'static str,
}
fn is_approved_license(spdx: &str, allowed: &[&str]) -> bool {
// A compound expression like "MIT OR Apache-2.0" passes if ANY branch is allowed
spdx.split(" OR ")
.any(|part| allowed.contains(&part.trim()))
}
fn main() {
let allowed = ["MIT", "Apache-2.0", "BSD-3-Clause"];
let crates = [
CrateLicenseCheck { name: "serde", spdx_expr: "MIT OR Apache-2.0" },
CrateLicenseCheck { name: "ring", spdx_expr: "Apache-2.0 AND ISC" },
];
for c in crates {
println!(
"Crate {:<8} ({:<18}) approved: {}",
c.name,
c.spdx_expr,
is_approved_license(c.spdx_expr, &allowed)
);
}
}
Crate serde (MIT OR Apache-2.0 ) approved: true
Crate ring (Apache-2.0 AND ISC) approved: false