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
- Set permissions on the job. For binaries, the documentation lists
id-token: write,contents: readandattestations: write. For container images, also addpackages: write. - Build your artifact as usual.
- Generate an SBOM as a JSON file with the tool you use. For container images the SBOM must be JSON.
- Add the attest step after the build. For binaries, set
subject-pathto the artifact. For images, setsubject-nameto the fully qualified image name without a tag,subject-digestto thesha256:digest, andpush-to-registry: true. - Add the SBOM by setting
sbom-pathon 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.
| Piece | Answers |
|---|---|
| Provenance attestation | Where and how was this built? |
| SBOM | What is inside? |
| Advisory scanning | Does 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
- GitHub docs, artifact attestations for build provenance: https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds
- GitHub docs, security hardening for GitHub Actions: https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions
Last reviewed: 19 October 2026.