Safeguard
Supply Chain•

How do I attach an SBOM and build attestation to a GitHub release?

Generate an SBOM, attest it in your release workflow with GitHub artifact attestations, and show users how to verify it with gh. Steps and permissions.

Safeguard Security Team
4 min read

Add an attestation step to your release workflow after the build, give the job the three required permissions, and point the step at your artifact and, if you have one, your SBOM file. Users then verify with gh attestation verify. The steps below follow GitHub's documentation.

What an attestation tells users

GitHub describes artifact attestations as a way to establish where and how your software was built. They provide build provenance for binaries and container images, and can also cover an SBOM. A user who downloads your release can check that the file came from your repository's workflow.

That is useful, but it is not a safety certificate. Provenance says where the file was built, not that the code or its dependencies are free of flaws. A compromised maintainer account can still produce a validly attested build.

Steps in the workflow

  1. Set permissions on the job. For binaries, the documentation lists id-token: write, contents: read and attestations: write. For container images, also add packages: write.
  2. Build your artifact as usual.
  3. Generate an SBOM as a JSON file with the tool you use. For container images the SBOM must be JSON.
  4. Add the attest step after the build. For binaries, set subject-path to the artifact. For images, set subject-name to the fully qualified image name without a tag, subject-digest to the sha256: digest, and push-to-registry: true.
  5. Add the SBOM by setting sbom-path on the same step.

The documented action is actions/attest. Check its documentation for the current version tag before you pin it, and pin the action to a full commit SHA as GitHub recommends for workflow actions.

permissions:
  id-token: write
  contents: read
  attestations: write

What users run

For a binary:

gh attestation verify PATH/TO/ARTIFACT -R ORG/REPO

For a container image, log in to the registry and use the oci:// prefix:

gh attestation verify oci://ghcr.io/ORG/IMAGE:tag -R ORG/REPO

For an SBOM attestation, add --predicate-type, for example https://spdx.dev/Document/v2.3 for SPDX, plus --format json and a --jq filter to inspect the SBOM contents.

Put these commands in your release notes or README so users do not have to guess.

Why an SBOM at all

An SBOM lists what your release contains. Downstream users can rescan it when a new advisory lands, without needing to unpack and analyze your build. That helps them answer "does this advisory affect the version we use" quickly.

PieceAnswers
Provenance attestationWhere and how was this built?
SBOMWhat is inside?
Advisory scanningDoes anything inside have a known flaw?

You need all three questions answered, and no single artifact answers them all.

Mistakes to avoid

  • Attaching an SBOM generated from a different build than the release. Generate it in the same job.
  • Granting broader permissions than the three above.
  • Describing the release as secure because it is attested. Say what the attestation proves.

Try it yourself

Click through it at your own pace, or open it full screen. See how an inventory lists components with versions, the same information an SBOM carries.

Quick check

Does an attestation prove my release has no vulnerabilities?

No. It proves where and how it was built. Vulnerability status needs scanning.

Do I need all three permissions?

For binaries, the documentation lists all three. Container images add a fourth for packages.

Safeguard generates and scans SBOMs and rescans them as advisories arrive, so users of your release can keep watching. See the free scan.

Sources

Last reviewed: 19 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.