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

SBOM for .NET and NuGet projects under the CRA

6 min read

On this page
  1. Turn on the NuGet lock file
  2. Generate the SBOM
  3. The runtime is part of the product
  4. From SBOM to vulnerabilities
  5. How Provetry helps
  6. 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). In .NET, the NuGet packages are only part of the answer. The runtime your application runs on is a component as well, and when you ship it with the product, its support dates become yours.

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

Turn on the NuGet lock file

PackageReference projects do not write a lock file unless you ask. Add this to each project, or to Directory.Build.props for the whole solution:

<PropertyGroup>
  <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

dotnet restore then writes packages.lock.json next to each project, with every direct and transitive package at its resolved version and content hash. Commit it, and restore with dotnet restore --locked-mode in CI, so a build fails instead of silently resolving different versions. Older projects that still use packages.config list their packages there.

Generate the SBOM

The CycloneDX module for .NET reads a solution or a project and writes CycloneDX:

dotnet tool install --global CycloneDX
dotnet-CycloneDX MySolution.sln -o sbom -F Json

For a solution, it aggregates every project; -rs follows project references from a single project instead. Test projects are among the solution’s projects, so exclude them (--exclude-test-projects), or point the tool at the project you actually ship.

Microsoft’s own sbom-tool takes another approach. It scans the build output and the source folder together, and writes SPDX:

sbom-tool generate -b ./publish -bc ./src -pn MyProduct -pv 2.4.0 -ps "Acme Ltd" -nsb https://acme.example/sbom -mi SPDX:3.0

It writes SPDX 2.2 by default; -mi SPDX:3.0 selects SPDX 3.0. Because it starts from the folder you publish, it describes the files that actually ship, with their hashes.

The runtime is part of the product

How you publish decides what is in the product:

  • Framework-dependent: the application expects a .NET runtime already installed on the customer’s machine. Your SBOM covers your packages; your documentation must say which runtime version is required, and that it must be kept up to date.
  • Self-contained (--self-contained), and every Native AOT build: the runtime, or the parts of it you use, ships inside your product. Its version is a component, and Microsoft’s monthly security updates become updates of your product.

Support dates follow the same logic. Support for .NET 8 and .NET 9 ends on 10 November 2026; .NET 10, a long-term support release, is supported until November 2028. A product shipped self-contained on .NET 8 stops getting runtime security fixes on that date, while the CRA expects you to handle vulnerabilities for the whole support period you announced (Article 13(8)). Check the end of support of the runtime against your own before you announce it.

From SBOM to vulnerabilities

NuGet checks packages against the GitHub advisory database during dotnet restore (NuGet Audit, on by default since the .NET 8 SDK), and dotnet list package --vulnerable --include-transitive lists what it finds. Look first at the vulnerabilities exploited in the wild, which can start the reporting clock, and record in a VEX statement why the others do not affect your product when they do not.

How Provetry helps

Provetry reads packages.lock.json, from your CI or from the files you upload, with the direct dependencies the lock file records, writes the SBOM of each release in CycloneDX, and in SPDX on paid plans, and watches every package for new and exploited vulnerabilities, every day on paid plans and every week on Free. You can also upload the SBOM written by CycloneDX for .NET or sbom-tool. Its CI step shows where your code imports a vulnerable package, with the file and line. For NuGet packages it never concludes that a package is unused, because namespaces do not reliably say which package they come from. For the runtime, set the end of your support period in the product’s profile, and compare it with Microsoft’s dates.

Sources