Technology · Developer Tools
Auditing Your Cargo Dependencies: cargo-audit vs cargo-vet, and What Actually Catches an Attack
cargo-audit checks for known CVEs after the fact. cargo-vet and cargo-crev check trust before you upgrade. Here's the real difference, working setup for both, and which one would have caught the arrayref attack.
Prathviraj Singh
5 min read
Sponsored
The arrayref supply chain attack we covered separately got caught in about two hours, but not by anything running inside the average Rust project’s own CI pipeline. It got caught by a third party manually watching for exactly this pattern. If your build process depends entirely on someone else noticing before you do, you have a gap. Here’s what actually closes it, what doesn’t, and how to set it up without turning every dependency bump into a research project.
Two different jobs, one confusing name overlap
Rust’s dependency-auditing tooling covers two genuinely different problems, and it’s worth being precise about which one you’re solving before you install anything.
Known-vulnerability scanning answers “does anything in my dependency tree have a publicly disclosed CVE?” cargo-audit is the standard tool here. It checks your Cargo.lock against the RustSec Advisory Database, a community-maintained list of crates with reported security issues, and fails your build if it finds a match.
Trust and review verification answers a completely different question: “has anyone actually looked at the source of this dependency before my build trusts it?” cargo-vet and cargo-crev both live here. Neither one knows or cares whether a crate has a CVE. They care whether a human, either you or someone in a trust network you’ve chosen to rely on, has reviewed the actual code.
The distinction matters because a brand-new malicious release, like the poisoned arrayref 0.3.10, has no CVE on day one. cargo-audit is blind to it by design, not by bug, because there is nothing yet to look up. That’s the whole reason the second category of tool exists.
Setting up cargo-audit
Installation and a first run:
cargo install cargo-audit
cargo audit
A clean project reports nothing found; a vulnerable dependency prints the advisory ID, the affected version range, and the patched version:
Crate: example-crate
Version: 1.2.0
Title: Use-after-free in buffer handling
Date: 2026-06-11
ID: RUSTSEC-2026-0042
Solution: Upgrade to >= 1.2.1
The version worth running is the one wired into CI, not the one you remember to run before a release:
# .github/workflows/audit.yml
name: cargo-audit
on: [pull_request, push]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: rustsec/audit-check@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
This fails the pull request the moment a dependency change introduces a known-vulnerable crate, which is early enough to matter, unlike catching it in production three weeks later.
Setting up cargo-vet
cargo-vet requires more upfront investment because it needs actual trust decisions, not just a database lookup. Initialize it in a project:
cargo install cargo-vet
cargo vet init
This creates a supply-chain/ directory tracking which dependencies are “audited” (someone reviewed the source), “exempted” (explicitly allowed without review, tracked so the gap is visible), or unaccounted for. Running cargo vet after that fails the build for anything unaccounted:
cargo vet
# error: 3 dependencies are missing from audits.toml:
# proc-macro-unrelated-crate 2.1.0
# ...
The realistic path for most teams isn’t auditing everything from scratch. cargo-vet supports importing existing audit sets from organizations that already review large swaths of the crates.io ecosystem:
cargo vet import mozilla https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml
cargo vet import google https://raw.githubusercontent.com/google/rust-crate-audits/main/audits.toml
That turns “review 400 transitive dependencies” into “review the ones Mozilla and Google haven’t already vouched for,” which is a tractable afternoon of work instead of a project that never gets scheduled.
What none of this catches
Be honest with yourself about the gap that’s left. Even a fully configured cargo-vet setup only enforces review before a new dependency or version is trusted; it does nothing to stop a build.rs script from doing damage once it’s running, because Cargo’s build-script sandboxing is still limited in what it isolates as of 2026. The arrayref payload ran inside build.rs, with the same filesystem and network access as any other process on that machine.
The mitigation that actually contains that risk lives at the infrastructure layer, not in Cargo: run builds inside containers or CI runners with restricted network egress, so a build script trying to phone home for a second-stage payload has nowhere to reach. That’s a change to your CI environment, not a cargo install away.
| Layer | Tool | Catches |
|---|---|---|
| Known CVEs | cargo-audit | Already-disclosed vulnerabilities in your lock file |
| Unmaintained / duplicate crates | cargo-deny | License issues, yanked crates, dependency bloat |
| Trust before upgrade | cargo-vet / cargo-crev | Unreviewed new dependencies or version bumps |
| Build-time execution | Sandboxed CI runners | A malicious build.rs reaching the network |
Where to actually start
Don’t try to retrofit all four layers onto an existing project in one sitting. Add cargo-audit to CI first, it’s a ten-minute setup with immediate, low-noise value. Add cargo-deny next for maintenance-status checks. Save cargo-vet for when you’re ready to import an existing trust set rather than auditing from zero, and treat build-script sandboxing as an infrastructure project with its own timeline, not a checkbox on this list.
The realistic goal isn’t “audit everything.” It’s closing the specific gap that let the arrayref attack work: nothing in a typical project’s CI pipeline would have questioned a routine-looking dependency bump, because nothing was set up to ask.
Frequently asked questions
- What's the difference between cargo-audit and cargo-vet?
- cargo-audit checks your dependency tree against the RustSec Advisory Database, a list of crates with publicly disclosed vulnerabilities, and flags any you depend on. It's reactive: it only knows about a problem after someone has reported it. cargo-vet is proactive: it requires a human, either on your team or in a trust network you subscribe to, to have actually read a crate's source and vouched for it before your build will accept it. cargo-audit catches known CVEs; cargo-vet is the closer thing to catching a brand-new malicious release before it's known to anyone.
- Would cargo-audit have caught the arrayref supply chain attack?
- No, not on the day it happened. cargo-audit only flags crates with a published RustSec advisory, and the malicious arrayref 0.3.10 release had no advisory until after the Rust Security Response Team identified and pulled it. A tool checking known vulnerabilities cannot catch a vulnerability nobody has reported yet. cargo-vet, if configured to require review before accepting new dependency versions, could have blocked the automatic pickup of the poisoned release, though only if someone had actually audited the new version before it was trusted.
- Is cargo-vet worth the setup effort for a small team?
- For a small team with a lean dependency tree, yes, if you scope it to new or updated dependencies rather than trying to retroactively audit everything you already depend on. cargo-vet supports importing trust from established audit sets published by larger organizations (Mozilla and Google both publish ones), so you're not auditing every crate from scratch, only the gaps between what they've reviewed and what you actually use.
- How do I stop a malicious build.rs script from running at all?
- As of 2026, Cargo's built-in sandboxing for build scripts is still limited; the most reliable mitigation today is running builds inside a container or CI runner with restricted network egress and filesystem access, so that even if a build.rs script tries to download and execute a remote payload, it has nowhere to reach. This is infrastructure-level protection, not a Cargo flag, and it's worth treating as a required part of your CI setup rather than a nice-to-have.
- Should I run these tools locally, in CI, or both?
- Both, but for different reasons. Running cargo-audit locally catches problems before you push, which is faster feedback for you. Running it in CI is the enforcement layer that stops a vulnerable dependency from merging even if someone forgets to run it locally or an update lands via a bot like Dependabot or Renovate that never touches a developer's machine at all.
Sources
Sponsored
More from this category
More from Technology
R.01 hdiutil Is Deprecated in macOS 27: Migrating Build Scripts to diskutil image
R.02 The ripgrep Segfault That Wasn't a musl Bug, or a ripgrep Bug
R.03 Rust's Portable SIMD Just Landed on the GPU. Here's Why That's a Bigger Deal Than It Sounds
Sponsored
Discussion
Join the conversation.
Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.
Sponsored