Skip to content

Verified Builds: SLSA Provenance and Sigstore Signing

AppSec · advanced · 9 min read · last reviewed 2026-08-31

Sigstore proves who built it, SLSA provenance proves how. Generation is nearly free on hosted CI; verification with a real policy is the project. Levels, steps, and the silent failures.

TL;DR

  • A signature proves a trusted identity vouched for an artifact. Provenance proves what went into it. Shipping one without the other leaves a supply chain gap.
  • Sigstore's keyless signing binds a signature to a CI workflow identity via OIDC and a short-lived certificate logged to a public transparency log, removing the private key nobody wanted to own.
  • SLSA v1.0 Build levels run 0 to 3. L1 and L2 on hosted CI are close to free; L3 requires the platform itself to prevent provenance forgery.
  • Verify at admission, not at build, and write policy against the attestation contents. A policy that only checks signature validity accepts anything signed by anyone.
  • Address artifacts by digest, never by tag. A tag is a mutable pointer, and an attacker with registry write access moves it.

A signed artifact proves who built it. A provenance attestation proves how. The two are different documents solving different halves of the same problem, and shipping one without the other leaves a gap large enough to drive a supply chain attack through.

The pattern will look familiar if you have implemented sender authentication: a certificate chain, a published verification key, a policy at the receiving end, and a set of failure modes that produce no error at all. Software supply chain attestation is the same architecture applied to build systems.

The two documents

Sigstore signs. Cosign produces a signature over an artifact, bound to an identity rather than to a long-lived private key. The identity comes from an OIDC token, typically the workflow identity of your CI job, and the ephemeral certificate is logged to a public transparency log. The claim is: this artifact was signed by this identity at this time.

SLSA describes. A SLSA provenance attestation is a signed statement, in the in-toto format, recording what built the artifact: the source repository and commit, the build platform, the entrypoint, and the parameters. The claim is: this artifact came from this source through this build.

You need both. A signature without provenance tells you a trusted identity vouched for a binary but not what went into it. Provenance without a signature is an unauthenticated text file.

The most common half-implementation is signing container images and calling it supply chain security. An attacker who compromises the build pipeline gets their artifact signed by your legitimate workflow identity. The signature is valid. It was always going to be valid. Provenance is what makes the compromise visible, and only if someone verifies it.

The SLSA levels, honestly

SLSA v1.0 defines Build levels 0 through 3. The numbering invites treating them as a maturity ladder to climb, and in practice the distance between them is very uneven.

LevelRequirementReal cost
Build L0NothingZero
Build L1Provenance exists and is availableLow. Often one CI setting
Build L2Provenance is signed by a hosted build platformLow if you use hosted CI, high if you self-host
Build L3Build platform prevents provenance forgery, runs isolatedReal engineering, or a managed platform that does it for you

Build L1 to L2 on a hosted runner is close to free. GitHub Actions artifact attestations and the SLSA generator reusable workflows both produce signed provenance from a few lines of YAML. That is the step almost every team should take this quarter.

Build L3 requires the platform itself to guarantee that a build cannot forge its own provenance, which means isolated, ephemeral build environments with signing keys the build steps cannot reach. If you run your own Jenkins, this is a project. If you use a hosted platform that implements it, it is a checkbox.

Step 1: Generate provenance in CI

Add attestation generation to your build workflow. On GitHub Actions, the artifact attestation action produces a signed in-toto statement bound to the workflow identity, published to the transparency log, and stored with the artifact.

The output records the repository, the commit SHA, the workflow file, and the trigger. That is the material you will later write policy against.

Step 2: Sign the artifact

Keyless signing with cosign, using the same workflow identity. No key to store, rotate, or leak, which removes the failure mode that killed most previous signing initiatives: nobody wanted to own the private key.

For container images, the signature and the attestation both live alongside the image in the registry, addressed by digest.

Step 3: Address by digest, never by tag

This step is short and it is the one that decides whether any of the rest matters.

A tag is a mutable pointer. Verifying a signature on myapp:latest verifies whatever latest points to at that instant, and an attacker with registry write access moves the pointer. Every verification step, every deployment manifest, and every policy rule must reference myapp@sha256:....

Step 4: Verify at admission, not at build

Verification that happens in the pipeline that produced the artifact proves nothing. The check has to run at the point of consumption: an admission controller in your cluster, a gate in the deployment step, or a policy engine in front of the registry.

Write the policy against the attestation contents, not just the signature validity:

  • The signing identity is a workflow in a repository you own.
  • The source repository matches an allowlist.
  • The build was triggered from a protected branch or a tag, not an arbitrary pull request.
  • The builder is the platform you expect.

A policy that only checks "is there a valid signature" accepts anything signed by anyone in the transparency log, which is everyone.

Step 5: Decide what happens on failure

Unlike agent verification, this one should fail closed in production, and that decision has to be made deliberately with a documented break-glass path. Teams that enable enforcement without a bypass procedure discover the gap during an incident, at the worst possible moment.

Run in audit mode first. Log every artifact that would have been rejected. Fix them. Then enforce.

The failure modes

FailureSymptomDetection
Signing enabled, verification never implementedEverything works, nothing is checkedAudit whether any deploy path rejects an unsigned artifact
Policy accepts any valid signatureA signed malicious artifact deploysReview the policy for identity and source constraints
Verification by tagAttacker moves the tagGrep manifests for tags in place of digests
Third-party dependencies unattestedYour build is L3, your inputs are L0Inventory with an SBOM, check which dependencies publish provenance
Transparency log unreachable, verification skippedSilent bypassTest the offline path explicitly

The last row deserves attention. Verification tooling that degrades to "allow" when it cannot reach the log has the same property as an SPF permerror: a network problem becomes a security bypass, invisibly.

Where the boundary sits

Attestation covers artifacts you build. It says nothing about the dependencies you pulled in, which is the more common attack path. An SBOM inventories what is inside; provenance records how the outside was assembled. Neither substitutes for the other, and a team that has SLSA L3 on its own builds while pulling unpinned transitive dependencies has secured the wrong end.

Should you do it?

You ship containers or packages to customers

Yes. Get to Build L2 with signed provenance this quarter, then implement admission verification with a real policy. The generation half is a day of work. The verification half is the project.

You deploy only internally

Do the generation anyway, because it is nearly free on hosted CI and it turns incident forensics from archaeology into a query. Defer admission enforcement until you have an audit-mode baseline.

You are chasing a compliance requirement

Be precise about which level the requirement names, and be honest about whether it applies to your builds or to your inputs. Most procurement questionnaires ask about the former while the risk lives in the latter.

You self-host your build system

Build L3 is a genuine engineering program for you. Reaching L1 and L2 first is still worth doing and does not commit you to it.

Key takeaways

  • Signing container images and calling it supply chain security is the most common half-implementation. An attacker who compromises the pipeline gets a valid signature from your legitimate workflow identity.
  • Verification inside the pipeline that produced the artifact proves nothing. It has to run at the point of consumption.
  • Run admission enforcement in audit mode first, and write the break-glass path down before you enforce. Teams that skip this find the gap during an incident.
  • Verification tooling that proceeds when the transparency log is unreachable turns a network failure into a silent security bypass, exactly like an SPF permerror.
  • SLSA L3 on your own builds while pulling unpinned transitive dependencies means you secured the wrong end. Provenance covers what you build; an SBOM covers what you pulled in.

Frequently asked questions

What is the difference between Sigstore and SLSA?
Sigstore signs: cosign binds a signature to an identity, typically a CI workflow, using a short-lived certificate recorded in a transparency log. SLSA describes: a provenance attestation records the source, build platform, entrypoint, and parameters. You need both.
What SLSA level should we target?
Build L2 with signed provenance from hosted CI is the right target for most teams and is close to free. L3 requires a build platform that prevents a build from forging its own provenance, which is a real engineering program if you self-host.
Why is keyless signing better?
It removes the long-lived private key that killed most previous signing initiatives, because nobody wanted to own, rotate, or protect it. The ephemeral certificate is bound to a verified workflow identity instead.
Is a valid signature enough to allow a deployment?
No. A policy that only checks signature validity accepts anything in the transparency log, which is everything. Constrain the signing identity, the source repository, and the trigger.
Does SLSA replace an SBOM?
No. Provenance records how the artifact was assembled; an SBOM inventories what is inside it. Most supply chain risk lives in dependencies, which is the SBOM's territory.

Related

← All How-To & Implementation guides