Safeguard
Supply Chain•

How do you attest build provenance for a container image on GitHub?

Add an attestation step after your image build, grant id-token, attestations and packages write, push by digest, then check it with gh attestation verify.

Safeguard Security Team
3 min read

To attest build provenance for a container image on GitHub, add GitHub's attest action after the image build, give the job id-token write, attestations write, contents read and packages write, pass the image name and its digest, and set push-to-registry. Consumers then check it with gh attestation verify.

What an attestation is

An attestation is a signed statement about an artifact: here, that this image digest was built by this workflow in this repository. It is a record of where something came from. It is not a statement that the image is free of vulnerabilities. For that, scan it. See what package provenance proves and what it does not.

Permissions the job needs

From GitHub's artifact attestations guide:

Artifact typePermissions
Binariesid-token write, contents read, attestations write
Container imagesThe same, plus packages write

Set them on the job, not the workflow. See least privilege GITHUB_TOKEN for a release workflow.

The step

- name: Generate artifact attestation
  uses: actions/attest@v4
  with:
    subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
    subject-digest: ${{ steps.push.outputs.digest }}
    push-to-registry: true

The guide says the image name must be fully qualified and must not include a tag. If you build with docker/build-push-action, you can take the digest from its digest output. That is why you attest the digest and not the tag. A tag can move; a digest cannot. See why sign the image digest, not the tag. Pin third party actions by commit SHA too, as in pin GitHub Actions to a SHA or a tag.

Verify it

For a container image, log in to the registry first, then run the oci form:

docker login ghcr.io
gh attestation verify oci://ghcr.io/ORGANIZATION_NAME/IMAGE_NAME:test -R ORGANIZATION_NAME/REPOSITORY_NAME

For a file, use the path form with the same repository flag. The guide notes these commands assume an online environment and points to a separate guide for offline verification.

Add an SBOM attestation

The guide says the action can attest an SBOM too, with SPDX or CycloneDX predicates, by adding the sbom-path input. To verify, add a predicate type flag with the SPDX document URL given in the guide. Create the SBOM with a tool of your choice. See attach an SBOM and signature to an image with OCI referrers.

Common mistakes

  1. Attesting a tag instead of a digest.
  2. Forgetting packages write, so push to the registry fails.
  3. Treating a verified attestation as proof the image is clean.
  4. Never running the verify command yourself. See verify your own release the way a user would.

Try it yourself

Click through it at your own pace, or open it full screen.

Click through the scan and compare the findings with what an attestation can and cannot tell you.

Safeguard scans container images and generates SBOMs; the free scan is at gold.safeguard.sh/scan.

Quick check

Does an attestation mean the image is secure?

No. It says where and how the image was built, not that its contents are free of flaws.

Why must I leave the tag off the subject name?

The guide says to use the fully qualified name without a tag, and to pass the digest separately.

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.