Introduction: What Is SLSA and Why Should You Care?
Supply-chain Levels for Software Artifacts — SLSA (pronounced “salsa”) — is a security framework created by Google and now maintained by the Open Source Security Foundation (OpenSSF). Its goal is deceptively simple: make it harder for attackers to tamper with the software you build and ship.
If you have followed high-profile incidents like SolarWinds, Codecov, or the flood of malicious npm packages, you already know why supply-chain security matters. SLSA gives you a concrete, incremental framework for how to address it.
The SLSA v1.0 specification (released April 2023) simplified the original model into a clear track — Build Levels 0 through 3 — each one adding stronger guarantees about the integrity of your build process and the provenance metadata it produces.
This guide walks through every level in plain language, gives you a checklist you can hand to your team on Monday morning, maps each requirement to real tools, shows you what provenance actually looks like, and lays out a step-by-step adoption roadmap. Let’s get started.
Quick Overview: The SLSA Build Track at a Glance
Before diving into each level, here is a comparison table so you can see the full picture.
| Aspect | Build L0 | Build L1 | Build L2 | Build L3 |
|---|---|---|---|---|
| Build Process | No requirements | Scripted, consistent build | Hosted build service | Hardened, isolated builders |
| Provenance | None required | Exists & available | Authenticated & service-generated | Unforgeable, isolated signing |
| Provenance Signer | N/A | Developer or CI | Build service itself | Hardened build service |
| Tampering Protection | None | Mistakes & documentation | Tampering after build | Tampering during & after build |
| Effort to Adopt | Zero | Low — hours to days | Medium — days to weeks | High — weeks to months |
Build Level 0 — The Starting Point (No Guarantees)
Build L0 is not really a level at all — it is the absence of any SLSA compliance. Every software project starts here by default.
What It Means in Plain Language
You have no formal requirements. Builds may happen on a developer laptop, with no record of what source code went in, what commands ran, or what came out. There is no provenance document. There is nothing to verify.
Checklist
- ☐ Nothing required — this is the baseline from which you improve.
What Provenance Looks Like at L0
It doesn’t exist. There is no attestation, no metadata, no signature. If someone asks “prove this binary came from that commit,” the honest answer is: you can’t.
Bottom line: L0 is where most organizations are today. The good news? Moving to L1 is surprisingly easy.
Build Level 1 — Provenance Exists
L1 is the first meaningful step. Its core promise: provenance exists and the build process is scripted.
Requirements in Plain Language
- Scripted build — The build is defined in code (a Makefile, Dockerfile, CI pipeline YAML), not a series of manual shell commands a developer runs by memory.
- Provenance is generated — The build produces a document that records, at minimum, who built it, what source was used, and what build process ran.
- Provenance is available — Consumers can actually download and inspect the provenance.
Checklist
- ☐ Build is fully defined in a build script or CI configuration file (no manual steps).
- ☐ Every build produces provenance metadata (in-toto / SLSA provenance format preferred).
- ☐ Provenance records: build platform, source repo, entry point, and output artifact digests.
- ☐ Provenance is published alongside the artifact (e.g., in a registry, OCI artifact, or public URL).
- ☐ The provenance format follows the SLSA Provenance v1 schema.
Tools That Satisfy L1
- GitHub Actions — Use the slsa-github-generator reusable workflows. They generate SLSA provenance automatically.
- GitLab CI — GitLab 15.x+ supports artifact attestation natively.
- SLSA Verifier —
slsa-verifierCLI to validate provenance on the consumer side. - Sigstore / Cosign — Sign and store provenance in Sigstore’s transparency log (Rekor).
- in-toto — The in-toto framework provides a specification and libraries for generating attestations.
What Provenance Looks Like at L1
A minimal SLSA v1 provenance document at L1 might look like this (simplified JSON):
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [{
"name": "my-app",
"digest": { "sha256": "a1b2c3d4..." }
}],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": {
"buildType": "https://github.com/slsa-framework/slsa-github-generator/...",
"externalParameters": {
"source": {
"uri": "git+https://github.com/acme/my-app@refs/heads/main",
"digest": { "sha1": "abc123..." }
}
}
},
"runDetails": {
"builder": {
"id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.9.0"
}
}
}
}
Key point: At L1 the provenance may be self-attested — the developer or their own CI job signs it. That’s okay at this level; the goal is existence.
Build Level 2 — Hosted, Authenticated Provenance
L2 raises the bar: the build must run on a hosted build service, and the provenance must be generated and signed by that service — not by the developer.
Requirements in Plain Language
- Hosted build platform — Builds run on a managed service (GitHub Actions, GitLab CI, Google Cloud Build, Jenkins on managed infra, etc.), not on a developer’s laptop.
- Authenticated provenance — The build service itself generates and signs the provenance. A developer cannot forge or modify it.
- Service-generated — Provenance generation is a feature of the build platform, not a script the developer can alter in their repo.
Checklist
- ☐ All release builds run on a hosted CI/CD service (no local builds for production artifacts).
- ☐ The build service generates provenance — not a user-controlled script.
- ☐ Provenance is signed by the build service’s identity (e.g., OIDC-based Sigstore keyless signing).
- ☐ Provenance includes authenticated builder identity (you can verify which service produced it).
- ☐ Consumers can verify the provenance signature against the build service’s known identity.
- ☐ Source repo and entry point in provenance are populated by the service, not user-supplied values.
Tools That Satisfy L2
- GitHub Actions + slsa-github-generator — When using the reusable workflow (not a composite action), GitHub’s OIDC token signs the provenance. This meets L2 out of the box.
- Google Cloud Build — Natively produces authenticated provenance for container images stored in Artifact Registry.
- Sigstore Fulcio + Rekor — Keyless signing with short-lived certificates tied to the CI’s OIDC identity. The transparency log (Rekor) provides a tamper-evident record.
- Tekton Chains — For Kubernetes-native CI. Tekton Chains automatically generates and signs SLSA provenance for Tekton pipeline runs.
- SLSA Verifier — On the consumer side,
slsa-verifier verify-artifactchecks the signature and builder identity.
What Provenance Looks Like at L2
The JSON structure is similar to L1, but the critical difference is the signature envelope. The provenance is wrapped in a DSSE (Dead Simple Signing Envelope):
{
"payloadType": "application/vnd.in-toto+json",
"payload": "<base64-encoded provenance statement>",
"signatures": [{
"keyid": "",
"sig": "MEUCIQD...base64...signature"
}]
}
The signature comes from the build service’s identity — verified via Sigstore’s certificate transparency log — not from a developer’s personal key. This is what makes the provenance authenticated.
Build Level 3 — Hardened Builds
L3 is the gold standard in SLSA v1.0. It adds isolation guarantees: the build environment is hardened so that even a compromised build script or malicious dependency cannot tamper with the provenance or other tenants on the build system.
Requirements in Plain Language
- Hardened build platform — The build service provides strong isolation between build jobs (e.g., ephemeral VMs, not shared containers). One job cannot influence another.
- Non-falsifiable provenance — The provenance is generated in a way that the build job itself (the user-defined code) cannot modify or forge. The signing key or OIDC identity is not accessible to the build script.
- Isolated secrets — The signing material (keys, OIDC tokens used for signing) is outside the tenant’s control. Even if the build script is fully compromised, it cannot produce a valid provenance attestation for an artifact it did not build.
Checklist
- ☐ Build jobs run in ephemeral, isolated environments (VMs, not long-lived shared runners).
- ☐ Build environments are freshly provisioned for each build and destroyed after.
- ☐ User-defined build steps cannot access the provenance signing key or token.
- ☐ The platform prevents one tenant’s build from influencing another’s.
- ☐ Provenance is generated by the platform after the build completes — not inline with user code.
- ☐ Hermetic or sandboxed builds are used where possible (no arbitrary network access during build).
- ☐ The builder identity in provenance is a verified, platform-controlled value.
- ☐ You have verified that your build platform’s threat model documents how it meets SLSA L3 isolation.
Tools That Satisfy L3
- GitHub Actions (with slsa-github-generator reusable workflows) — GitHub-hosted runners use ephemeral VMs. The reusable workflow runs in a separate job that the calling workflow cannot tamper with. This architecture meets L3 when using the official
slsa-github-generator. - Google Cloud Build — Builds run on ephemeral VMs with isolated signing. Google’s documentation explicitly maps Cloud Build to SLSA L3.
- Tekton Chains on hardened Kubernetes — When Tekton runs on nodes with VM-level isolation (e.g., gVisor, Kata Containers) and Chains handles signing externally.
- Buildkite with isolated agents — When agents run on ephemeral infrastructure (auto-scaled EC2 instances terminated after each job).
What Provenance Looks Like at L3
The provenance document format is the same as L2 — an in-toto statement wrapped in a DSSE envelope. The difference is not in the format but in the trust properties behind the signature. At L3:
- The signing identity is verifiably tied to a hardened build platform.
- The
builder.idfield references a builder that is known to meet L3 isolation requirements. - Verification tools like
slsa-verifiercheck the builder identity against an allowlist of known L3-compliant builders.
# Verify an artifact at SLSA Build L3
slsa-verifier verify-artifact my-app-linux-amd64 \
--provenance-path my-app-linux-amd64.intoto.jsonl \
--source-uri github.com/acme/my-app \
--builder-id https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.9.0
Step-by-Step Adoption Roadmap
Do not try to jump straight to L3. SLSA is designed for incremental adoption. Here is a practical roadmap.
Phase 1: Reach Build L1 (Week 1-2)
- Audit your builds. List every artifact you ship. How is each one built? On whose laptop? Which CI job?
- Script everything. If any build step is manual, move it into your CI configuration. Every build must be reproducible from a single command or trigger.
- Add provenance generation. For GitHub Actions, add the
slsa-github-generatorreusable workflow. For other platforms, integratein-totoattestation generation into your pipeline. - Publish provenance. Attach the provenance to your release artifacts. For container images, push it as an OCI artifact alongside the image. For binaries, publish the
.intoto.jsonlfile. - Verify it works. Use
slsa-verifierto confirm that the provenance is valid and the artifact digest matches.
Phase 2: Reach Build L2 (Week 3-6)
- Eliminate local builds. Enforce a policy: no production artifacts are built outside of CI. Use branch protection rules and required status checks.
- Switch to service-generated provenance. Move from self-attested provenance to platform-generated provenance. With GitHub Actions, this means using the reusable workflow (not a composite action). With GCB, enable built-in attestation.
- Enable keyless signing. Use Sigstore Fulcio for short-lived OIDC-based certificates. This ties the signature to the CI’s identity, not a long-lived key you manage.
- Add verification to your deployment pipeline. Before deploying, run
slsa-verifieror a policy engine (like Kyverno or OPA Gatekeeper) to check provenance on every artifact entering production.
Phase 3: Reach Build L3 (Month 2-4)
- Verify your platform’s isolation model. Read your CI provider’s security documentation. Does it use ephemeral VMs? Can one job access another’s environment? For GitHub-hosted runners, the answer is yes (ephemeral) — for self-hosted runners, you likely need to reconfigure.
- Migrate off shared or self-hosted runners (or harden them). If you use self-hosted GitHub Actions runners, move to ephemeral auto-scaled instances (e.g., Actions Runner Controller with ephemeral pods or AWS auto-scaling groups).
- Lock down the signing path. Ensure that the signing key or OIDC token used for provenance is not accessible to user build steps. With
slsa-github-generatorreusable workflows, this is enforced by design. - Document your threat model. Write down what your build platform protects against and what it does not. Share this with your security team for review.
Common Pitfalls
Even well-intentioned teams trip over these issues. Avoid them early.
- Using a composite action instead of a reusable workflow on GitHub. A composite action runs inside the caller’s job, meaning the caller can tamper with the provenance generation. Only a reusable workflow runs in a separate, isolated job. This is the difference between L1 and L2+ on GitHub Actions.
- Treating provenance as a checkbox. Generating provenance means nothing if nobody verifies it. Set up automated verification in your deployment pipeline — not just in an audit report.
- Storing signing keys in the repo or CI environment variables. This defeats the purpose. Use keyless signing (Sigstore) or an external KMS. The signing identity should not be accessible to the build script.
- Ignoring self-hosted runners. Self-hosted runners are often long-lived VMs shared across jobs. This breaks L3 isolation. Either move to ephemeral runners or use VM-level isolation.
- Skipping source verification. SLSA Build Track focuses on the build. But if an attacker can push malicious code to your repo, a perfectly compliant build just produces a tampered artifact with valid provenance. Pair SLSA with strong source controls (branch protection, code review, commit signing).
Frequently Asked Questions
Is SLSA only for container images?
No. SLSA applies to any software artifact — binaries, npm packages, Python wheels, Helm charts, Terraform modules, and more. The provenance format (in-toto) is artifact-agnostic.
Does SLSA replace SBOM?
No. They are complementary. An SBOM (Software Bill of Materials) tells you what’s in the artifact. SLSA provenance tells you how it was built and where it came from. Use both together for full supply-chain visibility.
Do I need L3 to be “compliant”?
Not necessarily. SLSA is a maturity framework, not a pass/fail regulation. L1 is already a meaningful improvement over L0. Many organizations target L2 as a practical sweet spot. L3 is for high-security environments or projects with strict supply-chain requirements (e.g., government, critical infrastructure).
How does SLSA relate to NIST SSDF or EO 14028?
Executive Order 14028 and NIST’s Secure Software Development Framework (SSDF) both call for supply-chain security practices that SLSA directly supports. SLSA provenance and build integrity are concrete implementations of SSDF practices like PS.1 (protect software) and PW.4 (archive and protect build processes). Adopting SLSA helps you tick many boxes in these frameworks.
What if my CI platform does not support SLSA natively?
You can still generate provenance using in-toto libraries and sign it with Sigstore. This gets you to L1. For L2+, you will likely need to add a provenance generation step that runs in a separate, trusted job or service that the main build cannot tamper with.
Further Reading and Resources
- Official SLSA Specification: slsa.dev/spec/v1.0
- SLSA Provenance Format: slsa.dev/provenance/v1
- slsa-github-generator: GitHub Repository
- slsa-verifier: GitHub Repository
- Sigstore: sigstore.dev
- in-toto: in-toto.io
- Our SLSA Provenance Guide: SLSA Provenance Deep Dive
- Hands-On Lab: SLSA Provenance Lab — Generate and Verify Your First Attestation
Conclusion: Start at L1, Ship on Monday
SLSA is not an all-or-nothing framework. The entire point of the level system is that you can start small and improve incrementally.
Here is your Monday morning action plan:
- Pick one artifact — your most critical binary or container image.
- Add provenance generation to its CI pipeline using
slsa-github-generatoror your platform’s equivalent. - Publish the provenance alongside the artifact.
- Verify it with
slsa-verifier. - Celebrate. You are now at SLSA Build L1 — ahead of the vast majority of software projects.
Then iterate. Move to L2 by ensuring the build service signs the provenance. Harden your runners for L3. Each step materially reduces your supply-chain risk.
The supply chain attacks will keep coming. The question is not whether to adopt SLSA — it’s how fast you can get there. Start today.