cargo-audit-rust
Configures and runs cargo-audit against the RustSec Advisory Database for Rust projects; covers `cargo audit` (vulnerability scan), `cargo audit fix` (automated dependency updates), `--deny unmaintained|unsound|yanked|warnings` exit-code control, `audit.toml` per-advisory suppression with mandatory `expires` + `reason`, SARIF output for GitHub Code Scanning upload, and `rustsec/audit-check` GitHub Actions integration. Use when the codebase has a Cargo.lock and needs Rust-specific SCA beyond what the multi-ecosystem npm-pip-maven-audit wrapper provides.
cargo-audit-rust
Overview
cargo-audit scans a project's Cargo.lock against the RustSec Advisory Database, a community-maintained vulnerability DB for Rust crates covering memory safety, cryptographic flaws, logic errors, malicious packages, and unmaintained crates (rustsec.org/advisories).
Differentiation from npm-pip-maven-audit: that skill lists cargo audit as one of eight native audit commands in a single wrapper. This skill covers the Rust-specific depth: --deny flag semantics, audit.toml suppression schema, cargo audit fix, SARIF output, binary auditing via cargo audit bin, and the rustsec/audit-check GitHub Action - none of which the multi-ecosystem skill documents.
When to use
Step 1 - Install
Per cargo-audit README:
cargo install cargo-audit --lockedMinimum Rust version: 1.74 per rustsec-readme.
Platform package managers (consult rustsec-readme for current availability):
# Alpine Linux
apk add cargo-audit
# Arch Linux
pacman -S cargo-audit
# macOS Homebrew
brew install cargo-auditTo enable the cargo audit fix subcommand, install with the fix feature (rustsec-readme):
cargo install cargo-audit --features=fix --lockedStep 2 - Basic scan
Run at the workspace root where Cargo.lock lives (rustsec-readme):
cargo auditScan a specific lockfile path (rustsec-readme):
cargo audit -f path/to/Cargo.lockcargo-audit fetches the RustSec Advisory Database on first run (a git clone into ~/.cargo/advisory-db). Pass --no-fetch to skip the fetch in air-gapped environments (rustsec-readme).
Step 3 - Exit codes and --deny flags
Exit codes per cargo-audit source:
| Code | Meaning |
|---|---|
| 0 | No vulnerabilities / denial criteria not triggered |
| 1 | Vulnerabilities found matching denial criteria |
| 2 | Execution error (missing lockfile, DB fetch failure) |
The --deny flag turns advisory categories into hard failures (cargo-audit source - audit.rs):
# Fail on any vulnerability
cargo audit --deny warnings
# Fail on unmaintained crates specifically
cargo audit --deny unmaintained
# Fail on unsound (memory-unsafe) crates
cargo audit --deny unsound
# Fail on yanked crates in the lockfile
cargo audit --deny yanked
# Combine: fail on vulnerabilities AND unmaintained
cargo audit --deny warnings --deny unmaintained--deny warnings is the special catch-all: it enables all denial categories simultaneously per audit.rs source.
Step 4 - Output formats
Per cargo-audit source, --format supports three values:
| Value | Use |
|---|---|
terminal | Default human-readable output |
json | Machine-readable; pipe to sca-prioritizer |
sarif | SARIF 2.1; upload to GitHub Code Scanning |
# JSON output for programmatic consumption
cargo audit --format json > cargo-audit.json
# SARIF output for GitHub Security tab
cargo audit --format sarif > cargo-audit.sarifStep 5 - audit.toml suppression
Persistent suppression belongs in .cargo/audit.toml at the repo root, not as CLI --ignore flags (which are not auditable in git). Per the audit.toml example:
# .cargo/audit.toml
[advisories]
# Advisory IDs to suppress - each MUST have a reason and expiry tracked in a
# companion comment or issue tracker entry
ignore = ["RUSTSEC-2024-0001"]
# Informational categories to surface as warnings (not hard failures)
informational_warnings = ["unmaintained", "unsound"]
# Minimum CVSS severity to report: "none" | "low" | "medium" | "high" | "critical"
severity_threshold = "medium"
[output]
# "terminal" | "json" | "sarif"
format = "terminal"
# Hard-fail categories (mirrors --deny flags)
deny = ["warnings"]
# Show inverse dependency trees alongside each finding
show_tree = true
[database]
# Skip remote fetch (for offline / air-gapped builds)
fetch = false
# Allow an advisory DB that has not been updated recently
stale = falseSuppression template (mandatory fields; absence of reason is an audit debt risk):
[advisories]
ignore = ["RUSTSEC-2024-0999"]
# RUSTSEC-2024-0999: serde_cbor unmaintained
# Reason: we use serde_cbor only in test fixtures, not in production paths.
# Approved-by: alice@example.com
# Re-review-date: 2026-09-30
# Tracking: JIRA-4567Commit .cargo/audit.toml to the repository so suppressions are auditable in git history and code review.
Step 6 - cargo audit fix
cargo audit fix automatically updates Cargo.toml version constraints to pull in patched crate versions, then runs cargo update (rustsec-readme):
# Preview changes without modifying files
cargo audit fix --dry-run
# Apply updates
cargo audit fixLimitations: cargo audit fix is experimental per rustsec-readme; it updates version constraints but cannot resolve conflicts in the dependency graph - manual intervention is needed when the patched version is incompatible with other constraints. Always run cargo test after applying fixes.
Step 7 - Binary auditing
For auditing compiled binaries (e.g. checking a deployed artifact without access to source), install the companion crate and audit the binary (rustsec-readme):
# Compile with embedded dependency metadata
cargo install cargo-auditable
cargo auditable build --release
# Audit the compiled binary
cargo audit bin target/release/my-appBinary auditing works best when the binary was compiled with cargo-auditable which embeds Cargo.lock metadata into the ELF/Mach-O/PE section.
Step 8 - GitHub Actions CI integration
Use the official rustsec/audit-check action, which wraps cargo audit, creates check runs, and (for scheduled workflows) opens GitHub Issues for each advisory per audit-check README:
name: Security audit
on:
push:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
schedule:
- cron: '0 0 * * *'
jobs:
security_audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: rustsec/audit-check@v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Optional: comma-separated advisory IDs to suppress
# ignore: "RUSTSEC-2024-0001,RUSTSEC-2024-0002"
# Optional: subdirectory with Cargo.toml
# working-directory: crates/my-crateCI gate behavior per audit-check-action:
For SARIF upload alongside the action:
- name: Run cargo audit (SARIF)
run: cargo audit --format sarif > cargo-audit.sarif || true
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: cargo-audit.sarifAnti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
--ignore RUSTSEC-xxxx in CI script | Not auditable in git; lost on script rewrite | Use [advisories] ignore in .cargo/audit.toml committed to repo |
No reason comment next to ignore | Silent debt accumulation | Mandatory reason + re-review date (Step 5 template) |
cargo audit without --deny | Vulnerabilities surface as warnings, not failures | Add --deny warnings or set deny = ["warnings"] in audit.toml |
Skip --format sarif upload | Findings invisible in GitHub Security tab | Emit SARIF + upload (Step 8) |
cargo audit fix without cargo test | A patched dep version may break compilation or tests | Always test after fix (Step 6) |
Omitting Cargo.lock from git (library crates) | cargo audit has nothing to scan | Commit Cargo.lock or generate it with cargo generate-lockfile in CI |