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.
| Level | Requirement | Real cost |
|---|---|---|
| Build L0 | Nothing | Zero |
| Build L1 | Provenance exists and is available | Low. Often one CI setting |
| Build L2 | Provenance is signed by a hosted build platform | Low if you use hosted CI, high if you self-host |
| Build L3 | Build platform prevents provenance forgery, runs isolated | Real 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
| Failure | Symptom | Detection |
|---|---|---|
| Signing enabled, verification never implemented | Everything works, nothing is checked | Audit whether any deploy path rejects an unsigned artifact |
| Policy accepts any valid signature | A signed malicious artifact deploys | Review the policy for identity and source constraints |
| Verification by tag | Attacker moves the tag | Grep manifests for tags in place of digests |
| Third-party dependencies unattested | Your build is L3, your inputs are L0 | Inventory with an SBOM, check which dependencies publish provenance |
| Transparency log unreachable, verification skipped | Silent bypass | Test 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
Research pillars
Vendor comparisons
Sibling guides