Visit NES for .NET Home Page

Software Bill of Materials (SBOM)

Where to find and download the CycloneDX SBOMs for NES for .NET 6 and .NET 8, how to check their signature and your download, and how to use them in Trivy, Grype, and Dependency-Track.

NES for .NET publishes a CycloneDX 1.6 SBOM for every installer and archive on the .NET 6.0.x and .NET 8.0.x pages. There is one SBOM per download, and its name is the file name of the download plus .cdx.json.

The SBOMs are generated from the files we ship, not from source, so they list what is in the download you install. Each one records the SHA-512 and SHA-256 of the file it describes.

What an SBOM lists

  • The shared frameworks in the download (.NET, ASP.NET Core, Windows Desktop) as pkg:nuget identities for the NES runtime packs, with the Microsoft release they descend from.
  • Every file in the download, with its SHA-512, SHA-256, file version, and SWHID, the identifier of the file's exact bytes.
  • Who made each component. NES builds name HeroDevs. Files Microsoft signed, and Microsoft builds we ship unchanged, name Microsoft, so a component's producer says whose build it is.
  • Native libraries that ship in the runtime, such as msquic.dll, and the native code Microsoft vendors into it, such as zlib and brotli. See MsQuic and HTTP/3 in .NET 6.
  • For an installer, each package inside it as its own entry. An .exe bundle lists every .msi it chains, with its product code and manufacturer, so the Microsoft MSIs in the SDK installer say so. A .deb or .rpm lists the packages it depends on.
  • For the SDK, the NuGet packages its tools were built from, the packs, and the templates.

An SBOM does not list vulnerabilities. That is the job of the VEX feed.

The SBOMs carry the CISA 2026 Minimum Elements for an SBOM: the format, author, tool, version, timestamp, and generation context of the SBOM itself, and a name, version, unique identifier, producer, hash, and license for each component. Where the license of a package isn't recorded anywhere we can read, the SBOM says NOASSERTION, and where its producer isn't known, the SBOM leaves it out rather than guess. Every SBOM is scored against those elements with sbomqs before it's published.

Each release's SBOMs are signed by HeroDevs. See Check the signature.

What is covered

DownloadCovered
.NET RuntimeWindows x64 and x86 (.exe, .msi, .zip) and Linux (.tar.gz, .deb, and on .NET 6 .rpm for RHEL 8+)
ASP.NET Core RuntimeWindows x64 and x86 (.exe, .msi, .zip), the Windows Hosting Bundle, and Linux (.tar.gz and .deb)
Windows Desktop RuntimeWindows x64 (.exe, .msi, .zip) and the targeting pack .msi
.NET SDKWindows x64 (.exe, .zip) and Linux (.tar.gz and .deb)

The host, hostfxr, apphost pack, and targeting pack installers each have their own SBOM too, as do the ASP.NET Core Runtime downloads for Windows arm64, the ASP.NET Core Module and IIS Express module installers, and the Hosting Bundle options installer. SBOMs for the NuGet packages and the Docker images are not published yet, and neither are SBOMs for the symbol, crossgen2, composite, and internal archives.

Where to find them

The SBOMs are in the NES registry, one package per .NET major version: dotnet-6-sbom and dotnet-8-sbom. The version is the runtime release, so the SBOMs for .NET 6.0.48 and SDK 6.0.439 are both under 6.0.48.

https://registry.nes.herodevs.com/bin/nes/dotnet-<major>-sbom/<runtime-version>/<download-file-name>.cdx.json

For example, with https://registry.nes.herodevs.com/bin/nes/ in front of the path:

DownloadSBOM path
dotnet-runtime-6.0.48-win-x64.exedotnet-6-sbom/6.0.48/dotnet-runtime-6.0.48-win-x64.exe.cdx.json
dotnet-hosting-8.0.33-win.exedotnet-8-sbom/8.0.33/dotnet-hosting-8.0.33-win.exe.cdx.json
windowsdesktop-runtime-8.0.33-win-x64.exedotnet-8-sbom/8.0.33/windowsdesktop-runtime-8.0.33-win-x64.exe.cdx.json
dotnet-sdk-6.0.439-win-x64.exedotnet-6-sbom/6.0.48/dotnet-sdk-6.0.439-win-x64.exe.cdx.json
el8-dotnet-runtime-6.0.48-linux-x64.tar.gzdotnet-6-sbom/6.0.48/el8-dotnet-runtime-6.0.48-linux-x64.tar.gz.cdx.json

Each version also has one signed catalog for all of its SBOMs, dotnet-<runtime-version>-sboms.cat, for example dotnet-8-sbom/8.0.33/dotnet-8.0.33-sboms.cat.

Download an SBOM

SBOM downloads use the same access token as the installers. See Downloading with an Access Token for the browser, and for how the credentials work.

Download with curl:

curl --fail --location \
     --header "Authorization: Bearer <NES_ACCESS_TOKEN>" \
     --remote-name \
     https://registry.nes.herodevs.com/bin/nes/dotnet-8-sbom/8.0.33/dotnet-hosting-8.0.33-win.exe.cdx.json

Download with PowerShell:

$token = "<NES_ACCESS_TOKEN>"
$basic = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("nes:$token"))

Invoke-WebRequest -UseBasicParsing `
  -Headers @{ Authorization = "Basic $basic" } `
  -Uri "https://registry.nes.herodevs.com/bin/nes/dotnet-8-sbom/8.0.33/dotnet-hosting-8.0.33-win.exe.cdx.json" `
  -OutFile "dotnet-hosting-8.0.33-win.exe.cdx.json"

Download every SBOM for a release

The signed catalog lists every SBOM for its release, so on Windows it's also the list of what to download. Download the catalog first, then each SBOM it names. This works in Windows PowerShell 5.1 and PowerShell 7 on Windows:

$version = "8.0.33"
$token   = "<NES_ACCESS_TOKEN>"
$base    = "https://registry.nes.herodevs.com/bin/nes/dotnet-$($version.Split('.')[0])-sbom/$version"
$basic   = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("nes:$token"))
$headers = @{ Authorization = "Basic $basic" }
$catalog = "dotnet-$version-sboms.cat"

New-Item -ItemType Directory -Force sboms | Out-Null
Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "$base/$catalog" -OutFile $catalog

$names = (Test-FileCatalog -Path sboms -CatalogFilePath $catalog -Detailed).CatalogItems.Keys
foreach ($name in $names) {
  Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "$base/$name" -OutFile "sboms\$name"
}

$signature = Get-AuthenticodeSignature $catalog
if ($signature.Status -ne 'Valid' -or
    $signature.SignerCertificate.Subject -ne 'CN=HeroDevs Inc., O=HeroDevs Inc., L=Sandy, S=Utah, C=US') {
  throw "The catalog does not have a valid HeroDevs signature."
}
$signature | Select-Object Status
Test-FileCatalog -Path sboms -CatalogFilePath $catalog

The last two lines print Valid when the catalog is signed by HeroDevs and every SBOM in the folder matches it. On Linux and macOS, download the SBOMs by name instead: each one is the name of the download it describes plus .cdx.json.

Check the signature

The SBOMs are signed with a Windows catalog file. dotnet-<runtime-version>-sboms.cat lists the SHA-256 of every SBOM for that version, and the catalog is signed by HeroDevs with Azure Artifact Signing and timestamped. Download it the same way as an SBOM, into the same folder.

Check the catalog's signature:

Get-AuthenticodeSignature .\dotnet-8.0.33-sboms.cat | Format-List Status, SignerCertificate

Status is Valid, and the signer is CN=HeroDevs Inc., O=HeroDevs Inc., L=Sandy, S=Utah, C=US. This is the same certificate subject that signs the NES installers.

Then check an SBOM against the catalog:

$sbom  = "dotnet-hosting-8.0.33-win.exe.cdx.json"
$items = (Test-FileCatalog -Path . -CatalogFilePath .\dotnet-8.0.33-sboms.cat -Detailed).CatalogItems
$items[$sbom] -eq (Get-FileHash $sbom -Algorithm SHA256).Hash

True means the SBOM is the one HeroDevs signed. False means it changed after it was signed.

If you downloaded every SBOM for the version into one folder, with nothing else in it, Test-FileCatalog checks them all at once and returns Valid:

Test-FileCatalog -Path .\sboms -CatalogFilePath .\dotnet-8.0.33-sboms.cat

On a folder that has only some of the SBOMs it returns ValidationFailed, because files the catalog lists are missing. Use the one-file check above in that case.

Check an SBOM against your download

The SBOM records the hash of the file it describes. Compare it with the hash of the file you downloaded. On Linux, use the commands below; on macOS, replace sha256sum with shasum -a 256:

sha256sum dotnet-hosting-8.0.33-win.exe
jq -r '.metadata.component.hashes[] | select(.alg == "SHA-256") | .content' dotnet-hosting-8.0.33-win.exe.cdx.json

On Windows:

(Get-FileHash .\dotnet-hosting-8.0.33-win.exe -Algorithm SHA256).Hash.ToLower()
(Get-Content .\dotnet-hosting-8.0.33-win.exe.cdx.json -Raw | ConvertFrom-Json).metadata.component.hashes |
  Where-Object alg -eq 'SHA-256' | ForEach-Object content

The two values match when the SBOM describes your file. If they differ, you have a different build than the SBOM, or the file changed after you downloaded it.

Scan an SBOM

Scanners match on the package URL of each component. The VEX feed names the NES runtime packs by the same URL, for example pkg:nuget/Microsoft.NETCore.App.Runtime.win-x64@6.0.48. Scan with the VEX document applied:

curl -sSL https://apps.herodevs.com/api/ontology/vex/statements -o herodevs.openvex.json
trivy sbom dotnet-runtime-6.0.48-win-x64.zip.cdx.json --vex herodevs.openvex.json

Or with Grype:

grype sbom:dotnet-runtime-6.0.48-win-x64.zip.cdx.json --vex herodevs.openvex.json

These commands were validated with Trivy v0.72.0 on October 23, 2026 and Grype v0.121.0 on October 26, 2026. Both match on the runtime pack's package URL: with the version set back to 6.0.10, Grype reports 12 advisories against pkg:nuget/Microsoft.NETCore.App.Runtime.win-x64@6.0.10. Neither scanner's database listed an advisory for 6.0.47 or 8.0.32 on those dates, so both reported nothing for what were then the current releases. See Scanner Workflows for pinning the scanner version in CI.

Load SBOMs into Dependency-Track

Dependency-Track reads CycloneDX, so each SBOM can be uploaded as it is, either from a project's Components tab with Upload BOM, or through the API with a key that has the BOM_UPLOAD permission. The example below also requires PROJECT_CREATION_UPLOAD to create the project if it does not already exist:

curl -X POST "https://<dependency-track>/api/v1/bom" \
     -H "X-Api-Key: <DEPENDENCY_TRACK_API_KEY>" \
     -F "autoCreate=true" \
     -F "projectName=dotnet-runtime-6.0.48-win-x64.zip" \
     -F "projectVersion=6.0.48" \
     -F "bom=@dotnet-runtime-6.0.48-win-x64.zip.cdx.json"

Dependency-Track 4.14.6 imported all 228 components of the 6.0.47 win-x64 runtime SBOM and 7,914 components of the 8.0.426 win-x64 SDK SBOM this way on October 26, 2026. Dependency-Track takes VEX in CycloneDX format, and the VEX feed is OpenVEX, so it doesn't apply the feed itself. Use Trivy or Grype for scans that need it.

When the SBOMs change

A release's SBOMs are written again whenever the files they describe change, for example when the Windows installers on a release are replaced with signed copies. Each SBOM gets a new serial number every time it's written, so match an SBOM to your download by the hash it records, as in Check an SBOM against your download, and not by its serial number.