Provetry opens in November 2026. The free CRA check, the tools and the guides are available now.

SBOM for Rust and Cargo projects under the CRA

6 min read

On this page
  1. Commit Cargo.lock
  2. Generate the SBOM
  3. Put the list inside the binary
  4. What the lock file does not show
  5. From SBOM to vulnerabilities
  6. How Provetry helps
  7. Sources

The Cyber Resilience Act asks every manufacturer to keep a software bill of materials “in a commonly used and machine-readable format covering at the very least the top-level dependencies” of the product (Annex I, Part II, point 1). Rust starts from a good place: Cargo.lock pins every crate with its checksum, and the RustSec advisory database often names the exact functions a vulnerability affects. What needs care is what the lock file lists but does not ship, and what ships without being listed.

For the regulation itself, see SBOM for the Cyber Resilience Act.

Commit Cargo.lock

For any binary you distribute, commit Cargo.lock and build with cargo build --locked. The lock file then records the exact crates and versions of the release. Direct dependencies are the ones declared in each Cargo.toml of the workspace.

Generate the SBOM

The CycloneDX project’s Cargo plugin asks Cargo for the resolved dependency graph:

cargo install cargo-cyclonedx
cargo cyclonedx --format json

It writes one file next to each Cargo.toml of the workspace. Two options matter for an accurate SBOM:

  • --target: Cargo.lock lists the dependencies of every platform, so a Linux build’s lock file still contains windows-sys. Pass the target you build for (it defaults to the host) to leave out what is not compiled in.
  • Features: the plugin follows Cargo’s feature selection. Use the same --features or --all-features choice as your release build.

Development dependencies are left out, since they cannot reach the binary.

Put the list inside the binary

cargo-auditable embeds the dependency list in the compiled executable, in a small compressed section:

cargo install cargo-auditable
cargo auditable build --release

The binary then describes itself. cargo audit bin ./target/release/app checks it against RustSec, and Syft, Trivy and Grype read it too. This is useful for the CRA when binaries end up in places where the original SBOM gets separated from them, such as firmware images, customer servers and container images.

Cargo itself is working on native support: an unstable -Z sbom flag writes “SBOM precursor” files next to the build output, and stabilising it is one of the Rust project’s goals for 2026.

What the lock file does not show

  • C code inside -sys crates. openssl-sys with the vendored feature compiles OpenSSL from the openssl-src crate; libsqlite3-sys with bundled compiles SQLite. The SBOM lists the crate, while the C library’s own advisories are published under OpenSSL’s or SQLite’s name. openssl-src carries the OpenSSL version in its own version number (300.x.y+3.x.y), so you can read it there; for other crates, note the bundled library and its version in the SBOM yourself.
  • Build scripts and procedural macros. build.rs and proc-macro crates run at compile time and are not in the binary as such, but they shape the code that is. They belong in the record as build-time components.
  • The Rust toolchain. The standard library is compiled into your binary. Its rare advisories are fixed in new Rust releases, so record the compiler version of each release.

From SBOM to vulnerabilities

cargo audit checks Cargo.lock against the RustSec advisory database, which OSV also republishes. RustSec advisories often list the affected functions (smallvec::SmallVec::insert_many), which lets you check whether your code calls them before deciding. Look first at the vulnerabilities exploited in the wild, which can start the reporting clock, and record in a VEX statement why a vulnerable function you never call does not affect the product.

How Provetry helps

Provetry reads Cargo.lock, from your CI or from the files you upload, takes direct dependencies from the Cargo.toml files, writes the SBOM of each release in CycloneDX, and in SPDX on paid plans, and watches every crate for new and exploited vulnerabilities, every day on paid plans and every week on Free. Its CI step goes one level further for Rust: when RustSec names the affected functions, only your own code depends on the crate, none of its macros is used, and none of the functions appears anywhere in your repository, it suggests “not affected” with that evidence. It draws no conclusion when Rust could call them without their name in the source: trait methods, operators, macros, derives, re-exports and code generated at build time. When a file does mention one, it gives the file and line to check first. Every finding is a suggestion, which you accept or not.

Sources