Creating SBOM Attestations for NuGet Packages Using GitHub Actions
In this blog post, Andrew Lock demonstrates how to create SBOM attestations for your .NET applications or NuGet packages using GitHub Actions, enhancing supply chain security.
Creating SBOM Attestations for NuGet Packages Using GitHub Actions
By Andrew Lock
Introduction
In this post, Andrew Lock provides a detailed guide on creating attestations for Software Bill of Materials (SBOM) documents for .NET applications and NuGet packages. The goal is to enhance confidence and transparency in the software supply chain by leveraging GitHub Actions for automated provenance and attestation generation.
Supply Chain Security and Attestations
Supply chain security involves ensuring the integrity and provenance of software artifacts. Andrew discusses the role of provenance attestations, which serve as standardized documents that describe how, where, and by whom an artifact was built (SLSA specification).
While providing an attestation doesn’t guarantee downstream security, it facilitates the verification process for package consumers, forming a key building block in supply chain security.
What is an SBOM?
A Software Bill of Materials (SBOM) enumerates the packages and dependencies used to create a software artifact. SBOMs enable:
- Visibility into included components
- Identification of known vulnerabilities
- Awareness of compliance/licensing issues
- Insight into supply chain risks
Combining Provenance and SBOM Attestations
Attestations can apply both to the artifact and to its associated SBOM, allowing consumers to verify that the SBOM is authentic and untampered, and was generated as claimed during a specific build run.
Generating SBOM Attestations in GitHub Actions
Andrew demonstrates how to use the actions/attest-sbom
GitHub Action to generate signed attestations for SBOMs. This action supports both SPDX and CycloneDX JSON formats. These formats are supported by multiple open-source tools and are standardized (SPDX: ISO/IEC 5692:2021, CycloneDX: ECMA-424).
Example Workflow: Building a .NET Project with SBOM Attestation
Below is a sample workflow that:
- Builds a .NET NuGet package
- Creates a CycloneDX SBOM
- Generates an SBOM attestation
name: BuildAndPack
on:
push:
branches: ["main" ]
tags: ['*']
pull_request:
branches: ['*']
jobs:
build-and-test:
# Add necessary permissions for attestation
permissions:
id-token: write
attestations: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/setup-dotnet@v4.3.1
with:
dotnet-version: "9.0.x"
- name: Build and pack
run: dotnet pack -c Release
- name: Push to NuGet
run: dotnet nuget push artifacts/packages/NetEscapades.AspNetCore.SecurityHeaders.nupkg
env:
NuGetToken: $
- name: Generate JSON SBOM
uses: CycloneDX/gh-dotnet-generate-sbom@v1.0.1
with:
path: ./src/NetEscapades.AspNetCore.SecurityHeaders/NetEscapades.AspNetCore.SecurityHeaders.csproj
out: ./artifacts/sboms
json: true
github-bearer-token: $
# Add this attestation step
- name: Attest package
uses: actions/attest-sbom@v2.2.0
with:
subject-path: artifacts/packages/NetEscapades.AspNetCore.SecurityHeaders.nupkg
sbom-path: artifacts/sboms/bom.json
Key Points:
- The workflow is set to run on every PR, branch, and tag by default, but can be restricted as needed (e.g., only on releases).
- The SBOM is generated in CycloneDX format, but SPDX is also supported.
- Attestation steps require additional permissions (
id-token: write
andattestations: write
).
Resulting Attestation Artifacts and Output
The actions/attest-sbom
action creates a Sigstore bundle (JSON document) representing the attestation, which includes information about:
- The artifact
- The SBOM
- The verification material (digital signatures, logs)
The run summary in GitHub Actions will also display attestation links for easy access.
If you click these links, you’re taken to a display page where you can view or download the attestation in a user-friendly format.
Verifying SBOM Attestations
Attestations add value only if they are verified by consumers. Andrew shows how verification can be performed using the GitHub CLI:
gh attestation verify \
--owner andrewlock \
--predicate-type https://cyclonedx.org/bom \
<filename-or-url>
- For SPDX SBOMs, use
--predicate-type https://spdx.dev/Document/v2.3
- If omitted, the CLI verifies the package’s provenance attestation by default
Example Output
gh attestation verify --owner andrewlock --predicate-type https://cyclonedx.org/bom "NetEscapades.AspNetCore.SecurityHeaders.1.0.0-preview.4.nupkg"
# ... output indicating policy, verification succeeded, and matching attestation information
Limitations for NuGet Packages
Verifying attestations for NuGet packages from nuget.org presents challenges:
- nuget.org modifies uploaded .nupkg files by adding its own signature file, invalidating earlier attestations
- Removing the added signature is only effective if the package isn’t author-signed
- Author-signed packages have their .signature.p7s file altered/countersigned, which can’t be “cleaned”
- Thus, provenance/SBOM attestations can’t always be reliably verified for packages retrieved from nuget.org
- However, NuGet native signatures provide some, but not equivalent, assurance
Summary
This guide builds on previous posts about provenance and SBOMs, describing how to automate SBOM attestation as part of the CI/CD workflow in GitHub Actions. While generating attestations is straightforward with available Actions, consuming/verifying attestations from nuget.org packages remains hindered by the repository’s modifications. Still, these practices illustrate good supply chain hygiene and point the way toward better security practices in the .NET ecosystem.
Author: Andrew Lock
.NET Escapades
This post appeared first on “Andrew Lock’s Blog”. Read the entire article here