Safeguard
Developer Tools•

Why does a GitHub attestation workflow need id-token and attestations?

GitHub's artifact attestation workflow asks for id-token, contents and attestations permissions, plus packages for images. Here is what each one is for.

Safeguard Security Team
3 min read

A GitHub workflow that creates build attestations needs id-token: write, contents: read and attestations: write, and also packages: write for container images. Each grants a specific capability, so set them at the job level and keep every other job at read only.

The permissions block is short, but it is a good place to apply least privilege.

The block from GitHub's documentation

For binaries, the documented workflow uses:

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

For container images, add packages: write. The documentation uses the actions/attest action, with subject-path for binaries, and subject-name, subject-digest and push-to-registry: true for images. SBOM attestations add sbom-path.

What each permission is for

PermissionPlain meaning
id-token: writeLets the job request an OpenID Connect token that identifies the workflow run
contents: readLets the job read the repository
attestations: writeLets the job store the attestation
packages: writeLets the job push the image and its attestation to the registry

The identity token is the interesting one. It is how a job can prove who it is without a stored secret, which is the same idea the Sigstore overview describes for keyless signing, where a certificate authority checks an identity token. Check GitHub's own documentation for how its attestations use that token, since this post only relies on what the page lists.

Applying least privilege

Workflow permissions can be set at the top of the file or per job. Prefer per job.

  1. Set a read only default for the whole workflow.
  2. Give the attestation job the block above, and nothing more.
  3. Keep jobs that run untrusted or third party steps separate from the job that holds id-token: write.
  4. Pin actions you use to a full commit SHA where your policy allows it.

Splitting jobs matters because any step in a job with id-token: write can request that token. A step you did not review, running in the same job, could use it.

Common mistakes

  • Granting write-all at workflow level because it "fixes" a permissions error.
  • Adding packages: write to binary only workflows.
  • Running pull request builds from forks in the same workflow that attests releases.
  • Forgetting that attestations describe a build, not the safety of what was built.

Verification is the other half

The documentation shows consumers verifying with gh attestation verify. An attestation nobody verifies is a record, not a control. Decide who checks and where, for example in a deploy job.

For container image workflows, also consider where scanning happens. Safeguard policies and gates can block pull requests that add risky dependencies, and the free scan at https://gold.safeguard.sh/scan is a quick check of what you ship.

Quick check

Can I put these permissions on the whole workflow?

You can, but per job is safer, because every step in a job with id-token write can request the token.

Do I need packages write for a binary?

The documentation adds packages write for container images, not for the binary example.

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.