Open Source Security

Rust Supply Chain: cargo-vet Expansion in 2025

Mozilla and Google expanded cargo-vet's shared audit pool to 14,000 crates in Q1 2025. Here's how to adopt it without drowning in imports.

Nayan Dey
Senior Security Engineer
5 min read

Rust's crate ecosystem crossed 170,000 published crates in March 2025, and 18 billion monthly downloads. The growth brought predictable supply chain anxiety: Socket's 2024 threat report catalogued 42 confirmed malicious crates, and the xz-utils backdoor (CVE-2024-3094, February 2024) reminded every language community that multi-year grooming attacks are real. Against this backdrop, cargo-vet — Mozilla's collaborative audit tool released to 1.0 in November 2023 — gained serious institutional adoption. By March 2025, Google, Mozilla, Zulip, Embark Studios, Fermyon, and ISRG jointly maintained audit records covering 14,140 distinct crates and 58,900 crate-versions, up from roughly 4,200 crates at the start of 2024. For a typical Rust binary with 400 dependencies, the shared pool now covers 60-75% of the graph — turning cargo-vet from an aspirational policy into a shippable control.

What does cargo-vet actually guarantee?

It guarantees that a human (or reviewer-trusted automated check) looked at the crate source at a specific version and confirmed it meets a stated criteria. The built-in criteria are safe-to-deploy (no malicious code, no unsafe surprises) and safe-to-run (same, but for dev-dependencies). You can define custom criteria — does-not-implement-crypto, no-network-io, constant-time. cargo-vet is not SBOM tooling and is not vulnerability scanning; it is a policy layer enforcing "no crate-version ships into our build without a recorded human audit." That policy, applied consistently, is what would have caught the event-stream (2018) and ua-parser-js (2021) classes of attack before they reached production.

How do we bootstrap without auditing everything?

Start with cargo vet init and accept the initial suggestion to "exempt" your current dependency tree — this marks your pinned versions as grandfathered and requires audits only for new additions or upgrades. From there, import audits from trusted organizations:

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

[imports.mozilla]
url = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"

[imports.isrg]
url = "https://raw.githubusercontent.com/divviup/libprio-rs/main/supply-chain/audits.toml"

[policy.default]
criteria = "safe-to-deploy"

After running cargo vet, the tool prints which crates still need your attention. The typical first-run result for a medium-sized service is 30-80 outstanding audits — manageable as a two-week engineering allocation.

What does a good audit look like?

A one-paragraph written record, bound to a specific version range. For a tiny crate you can genuinely skim, document it:

[[audits.serde_yaml_ng]]
version = "0.10.0"
criteria = "safe-to-deploy"
notes = """
Reviewed diff from 0.9.34. Upstream fork of dead serde_yaml. No unsafe blocks.
Uses libyaml via yaml-rust2 which we have already audited. No network or fs I/O.
"""

For large crates, delta-audits let you certify the diff from a known-good version without re-reading the whole crate. The convention in the Mozilla pool is to require delta-audits under 500 LOC and full audits otherwise.

How does cargo-vet interact with RustSec advisories?

They are complementary. cargo-vet certifies "this code was reviewed"; RustSec's cargo audit reports "this version has a known CVE." You need both. The typical CI pipeline runs them sequentially:

cargo vet --locked
cargo audit --deny warnings
cargo deny check advisories bans licenses sources

Failing any step fails the build. The 2024 RUSTSEC-2024-0003 advisory (an unsoundness in rustls-native-certs below 0.7.1) was caught in most adopter repos within 48 hours precisely because this three-tool gate was already in place.

What about the proc-macro problem?

Proc-macros are the highest-risk crates in any Rust graph because they execute arbitrary code at compile time. cargo-vet has no special handling — the audit is the audit — but the best practice emerging in 2025 is to declare a stricter safe-to-compile criterion for proc-macros:

[[criteria]]
name = "safe-to-compile"
description = "No filesystem or network access at macro expansion time."
implies = "safe-to-deploy"

[policy.syn]
criteria = ["safe-to-deploy", "safe-to-compile"]

This surfaces, for example, any proc-macro that opens network sockets during build — the exact pattern the xrcd malicious crate (removed from crates.io on March 3, 2025) exhibited.

How do we make this sustainable?

Publish your own audits. Every crate your team reviews privately should, when legally possible, land in a public audits.toml. The network effect compounds: Google's March 2025 retrospective reported that the marginal cost of a new adopter joining the pool dropped from 400 audit-hours to 120 audit-hours over the prior 12 months. Treat audit publication as you would CVE disclosure — a public good that improves your own security posture by ensuring upstream scrutiny.

How Safeguard Helps

Safeguard ingests cargo-vet audit records as a first-class SBOM attestation source, correlating them with CycloneDX component identities and RustSec advisories. Griffin AI performs reachability analysis on flagged crate-versions so you can prioritize auditing the transitive dependencies actually invoked by your binary rather than the full graph. TPRM workflows score upstream maintainers against commit-signing, release-cadence, and maintainer-count signals pulled from crates.io and GitHub, flagging high-impact single-maintainer crates before they become the next xz-utils. Policy gates block CI runs when a pull request introduces a crate without a matching audit in your trust pool, and Safeguard's VEX support suppresses RustSec findings that reachability analysis has proven non-exploitable.

Never miss an update

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