Safeguard
Software Supply Chain•

How do you generate an SBOM for a Rust project?

Commit Cargo.lock, run cargo cyclonedx for a CycloneDX file, embed dependency data with cargo auditable, and run both only on code you trust.

Safeguard Security Team
5 min read

To generate an SBOM for a Rust project, commit your Cargo.lock, install cargo-cyclonedx and run cargo cyclonedx in the project directory to produce a CycloneDX file. For shipped binaries, build with cargo auditable so the dependency list travels inside the executable. Run these tools only on code you trust.

Why does Rust need two kinds of SBOM?

An SBOM, in the NTIA's description, is a nested inventory for software, a list of the ingredients that make up its components. For a Rust application there are two moments when you might want to record it. At source time, the list comes from Cargo.lock. At artifact time, you want the list tied to the binary you actually shipped, so that a scanner can look at the executable months later without access to the repository.

The Cargo Book explains the base layer. Cargo.toml describes dependencies in a broad sense and is written by you. Cargo.lock holds exact information about them, is maintained by Cargo, and the book advises checking it into version control when in doubt. Without a lockfile, two builds on two days can resolve different versions, and any SBOM would describe only one of them.

How do you produce a CycloneDX file from source?

The OWASP CycloneDX project maintains a Cargo plugin. Its README gives the steps: install it with cargo install cargo-cyclonedx, then run it from a directory that contains Cargo.toml, either as the binary or as the Cargo subcommand cargo cyclonedx. It creates a valid CycloneDX SBOM with an aggregate of all project dependencies.

CycloneDX itself is an OWASP Foundation specification that is also standardised as ECMA-424. The overview page lists version 1.7 as current, with JSON, XML and protobuf forms. For most pipelines the JSON file is the one to store and send.

For a workspace with many crates, decide what the SBOM describes. One file per shipped binary is usually more useful than one file for the whole repository, since customers care about what is in the thing they run.

How do you attach the list to the binary?

The cargo-auditable project embeds the dependency tree, as JSON, into a dedicated linker section of the compiled executable. The README says Linux, Windows and macOS are officially supported, and that the embedded list uses under 4 kB even for trees of 400 or more entries. You install it with cargo install cargo-auditable, build with cargo auditable build plus your usual release option, and later scan the binary with cargo audit bin pointed at the executable.

The README also lists consumers: cargo audit, Trivy, Grype and OSV-Scanner can detect the data and report vulnerabilities, and Syft can recover it and convert to other formats. Distribution maintainers build packages this way, which means you can sometimes audit a system package with no source.

Is it safe to run the generator?

Read the security note in the CycloneDX plugin README. It says cargo-cyclonedx calls into Cargo internally, and like nearly any build system, Cargo may run arbitrary code when invoked on an untrusted project, so the tool should not be called on untrusted projects. Tools that only parse Cargo.lock still need Cargo to have generated that file. So run SBOM generation inside the same isolated, secret-free environment you use for builds, not on a repository you merely downloaded to inspect.

A constructed example

A team ships a command line tool. Their release job checks out a tagged commit, confirms Cargo.lock is unchanged from the tag, builds with cargo auditable, runs cargo cyclonedx for the source level file, and uploads the binary, the SBOM and a checksum together. Six months later a vulnerability is announced in a transitive crate. The security team does not rebuild anything. They scan the stored SBOMs and the binaries in the field, and find the two releases that include the affected version.

What to do

  1. Commit Cargo.lock for every binary crate.
  2. Install cargo-cyclonedx and generate a CycloneDX JSON file in the release job.
  3. Build release binaries with cargo auditable.
  4. Store the SBOM with the artifact, named by version and commit.
  5. Run generation in a sandboxed job with no deployment secrets.
  6. Scan SBOMs and binaries on a schedule, not only at release.
  7. Record which workspace members are included.
  8. Keep SBOMs for as long as you support the release.

Safeguard generates and analyses SBOMs through its CLI and dependency inventory, see the dependency inventory demo.

Quick check

Does an SBOM from Cargo.lock include crates that were not compiled?

It can list everything resolved in the lockfile, including optional or platform specific crates. Check how your tool treats features and targets, and prefer binary level data for what shipped.

Is it safe to generate an SBOM for a repository I do not trust?

No. Cargo may run arbitrary code on an untrusted project, so use an isolated environment.

Sources

Last reviewed: 18 October 2026.

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.