Skip to content

SLSA Explained: Supply-Chain Levels for Software Artifacts

Lesson 3 of 10Advanced15 min readGit Security & DevSecOps · Supply Chain SecurityVerified: SLSA specification v1.2 (Build and Source tracks); GitHub artifact attestations documentation, September 2026

SLSA — Supply-chain Levels for Software Artifacts — is a framework for describing how much you can trust a claim about how a piece of software was built.

It is not a tool, a scanner or a certification. It is a vocabulary with defined levels, so that “our builds are secure” can be replaced by a statement that means something specific and that somebody else can evaluate.

A track covers one aspect of supply-chain security. Each track has its own levels measuring increasing assurance about that aspect.

Two tracks are defined in v1.2.

About the integrity of the build process and the trustworthiness of the provenance describing it. Quoting the specification:

LevelSummary
Build L0“No guarantees — L0 represents the lack of SLSA”
Build L1“Package has provenance showing how it was built”
Build L2“Forging the provenance or evading verification requires an explicit ‘attack’, though this may be easy to perform”
Build L3“Forging the provenance or evading verification requires exploiting a vulnerability beyond most adversaries”

What distinguishes them:

L0 has no requirements. A developer building on their laptop is L0, and that is appropriate for development and test builds.

L1 requires a consistent build process on a platform that automatically generates provenance describing what was built and how. The provenance may be unsigned. L1 defends against mistakes and against nothing else — unsigned provenance is trivially forged.

L2 adds that builds run on a hosted platform that generates and cryptographically signs the provenance, with consumers validating its authenticity. Forging now requires an actual attack rather than editing a file.

L3 adds a hardened hosted platform: strong controls preventing runs from influencing one another, and preventing secret material from being accessible to user-defined build steps. This is the level at which a compromised build step cannot forge provenance for a different build.

Read the L2-to-L3 distinction carefully, because it is the one that determines what real work is involved. L2 is about the platform signing. L3 is about the platform being isolated enough that the thing being built cannot influence the signing.

New in v1.2, and it covers how a source revision was produced — the questions the Build track assumes somebody else answered.

LevelRequirement
Source L0No attestation issued for the revision
Source L1“The source is stored and managed through a modern version control system”
Source L2“Branch history is continuous, immutable, and retained, and the SCS issues Source Provenance Attestations for each new Source Revision”
Source L3“The SCS is configured to enforce the Organization’s technical controls for specific Named References within the Source Repository”
Source L4“The SCS requires two trusted persons to review all changes to protected branches”

Note that the Source track has four levels while the Build track has three. This is exactly why “we are SLSA Level 3” is not a meaningful sentence without naming the track.

The Source track maps onto material from earlier in this pillar more directly than the Build track does. Source L2’s “continuous, immutable, retained branch history” is blocking force pushes and restricting deletions. Source L3’s “enforce the organisation’s technical controls” is organisation-level rulesets. Source L4’s two reviewers is required reviews with a count of two.

GitHub Actions with artifact attestations produces signed provenance generated by the platform rather than by your workflow, which is the L2 property.

For Build L3, GitHub’s own documentation is specific: “Building software with reusable workflows and artifact attestations can streamline your supply chain security and help you achieve SLSA v1.0 Build Level 3.”

Two components are required:

Move the build steps into a reusable workflow. This is what creates the isolation boundary — the identity in the provenance is the reusable workflow, not the calling workflow, so the caller cannot influence what the provenance claims about the build.

The reusable workflow must generate the attestations. Attesting from the caller would defeat the point.

.github/workflows/build.yml (reusable)
on:
workflow_call:
permissions:
contents: read
id-token: write
attestations: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Build
run: ./build.sh
- uses: actions/attest-build-provenance@v4
with:
subject-path: dist/my-binary

The Build track is a framework around a document, and the document is worth looking at, because the levels are statements about how much that document can be trusted rather than about what is in it.

Provenance describes, in the specification’s terms, “what entity built the package, what build process they used, and what the top-level input to the build were”. Concretely that means a subject — the artifact, identified by digest — and a set of claims about its construction:

subject the artifact's name and digest
builder the identity that performed the build
buildType the kind of build process
invocation what triggered it, and with what parameters
resolvedDeps the top-level inputs — the source repository and commit
metadata when it started and finished

At L1 that document exists and is unsigned, so anybody can write one. At L2 the platform signs it, so the claim is attributable. At L3 the platform is isolated enough that the build being described cannot tamper with the description.

Nothing about the document changes between levels. What changes is who could have written it, and that is the entire content of the Build track.

Build provenance covers the document in detail, and artifact attestations covers GitHub’s implementation.

The levels are cumulative and the effort is not evenly distributed.

  1. Reach Build L1. Build on a platform that generates provenance. On GitHub Actions this is close to automatic — add the attestation step.

  2. Reach Build L2. Signed provenance generated by the platform. Adding actions/attest-build-provenance in a GitHub-hosted job gets you here, because GitHub signs rather than your workflow.

  3. Reach Build L3. Move the build into a reusable workflow that generates the attestations, so the caller cannot influence the provenance.

  4. Have consumers verify. Not a level requirement, and the step without which none of the above changes anything. Provenance nobody checks is a file.

  5. Address the Source track. Protected branches with immutable history, organisation-enforced rulesets, and required reviews. Most of this is Repository Security work you may already have done.

Step 4 is not on the SLSA ladder and is the step that produces the security benefit. It is worth being clear about that: SLSA levels describe the producer’s process. Verification is the consumer’s control. An organisation that reaches Build L3 and never verifies anything it consumes has improved what it publishes and not what it runs.

Levels are easier to justify when mapped to threats rather than to requirements.

ThreatStopped fromBy
A build script silently produces something other than the source specifiesBuild L1 onwardProvenance records the source and process, so a mismatch is detectable
Somebody hand-writes provenance for an artifact they built elsewhereBuild L2The platform signs it; forging requires attacking the platform
A malicious build step forges provenance for a different artifactBuild L3Build steps are isolated from the signing material
A build step exfiltrates the platform’s signing keyBuild L3Secret material is not accessible to user-defined steps
History is rewritten to hide what was in a releaseSource L2Branch history is continuous, immutable and retained
A repository’s protections are relaxed locally to land a changeSource L3Controls are enforced by the source control system, organisation-wide
A single compromised account lands a changeSource L4Two trusted persons must review

Two observations from that table.

The Build track is about the provenance’s trustworthiness, not the build’s correctness. Every row concerns whether you can believe the record. None concerns whether the build did something sensible.

The Source track rows are the ones most organisations can satisfy this week. They are repository configuration — the same controls described in Repository Security — rather than build platform engineering.

A level is a producer-side property. The consumer-side action is a verification policy: a statement of what provenance you require, from whom, before you use an artifact.

Terminal window
{/* Require that this image was built by a specific workflow in a specific repository */}
gh attestation verify oci://ghcr.io/YOUR_ORG/YOUR_IMAGE:TAG --repo YOUR_ORG/YOUR_REPO --signer-workflow YOUR_ORG/YOUR_REPO/.github/workflows/release.yml

The --signer-workflow constraint is what makes this a policy rather than a check. Verifying that some attestation exists proves very little; verifying that the attestation names the workflow you expect is the assertion that matters, because it is what a compromised build in a different repository cannot satisfy.

A useful policy states, at minimum:

  • Which repository the artifact must have been built from
  • Which workflow must have built it
  • Which ref it must have been built from — a release tag, or the default branch
  • What happens on failure, which must not be “log a warning”

That last point is where policies usually fail in practice. A verification step that reports and continues is documentation. See Secure release pipelines for where the check belongs.

It says: the build process has these properties, and the provenance has this degree of trustworthiness.

It does not say: the code is secure, the dependencies are safe, the artifact is free of vulnerabilities, or the build is reproducible.

An artifact at Build L3 can be riddled with vulnerabilities. Every SLSA claim about it is true: it was built by a hardened platform, from a stated source, with signed provenance. SLSA describes the process, not the product.

SLSA is usually discussed from the producer’s side. The consumer’s side is where it changes your own risk, and it is worth a separate treatment because the questions are different.

For each significant input to your builds — base images, third-party actions, language runtimes, key libraries — three questions:

Does it publish provenance at all? A growing number of ecosystems do. npm packages published with provenance, container images with attestations, GitHub Actions from repositories that attest their releases. Where provenance exists, verification is available and mostly unused.

Can you verify it? For a container image, cosign verify-attestation or gh attestation verify. For an npm package, the registry exposes provenance for packages published with it. The mechanics are covered in Sigstore and Artifact attestations.

What would you do if verification failed? The question that determines whether verifying is a control or a formality. A build that logs “provenance verification failed” and continues has added a line to a log.

A pragmatic starting point that is not a programme: verify the inputs to your most sensitive pipeline. The release workflow that signs and publishes your artifacts is the one where a compromised input has the widest blast radius, and it usually has few enough inputs to enumerate in an afternoon.

The asymmetry worth acting on: publishing provenance protects your consumers, and verifying provenance protects you. Organisations reliably do the first because it is visible, and skip the second because it is not.

Threat. An artifact is deployed that was not built from the source it claims, by the system it claims — and nothing in the pipeline can establish that.

Attack surface. The build platform, the build definition, the build’s inputs, and the storage between build and deployment. Plus the provenance itself, if anything other than the platform can write it.

Impact. A compromised artifact distributed through your own trusted channel, running with your production access, indistinguishable from a legitimate release.

Control. Provenance generated by the platform (L1), signed by it (L2), from an isolated build (L3) — and a consumer-side policy that refuses artifacts whose provenance does not match expectations.

Verification. Take an artifact from your registry and verify its provenance from a machine that was not involved in building it, asserting the specific repository and workflow you expect. If that check does not exist, or exists and does not fail the deployment, the levels you have reached are descriptive rather than protective.

Where SLSA fits among the other frameworks

Section titled “Where SLSA fits among the other frameworks”

SLSA is one of several things in this space and it is easy to conflate them. Each answers a different question.

Answers
SLSAHow much can I trust the claim about how this was built?
SBOMWhat is inside it?
SigstoreHow was this signed, and can I verify it without key management?
in-totoHow is a claim about a step in the supply chain expressed?
OpenSSF ScorecardWhat development practices does this project follow?

They compose rather than compete. In a GitHub Actions pipeline generating artifact attestations, the arrangement is roughly:

in-toto supplies the attestation format — the structure of “here is a statement about this subject”. Sigstore supplies the signing and transparency, so the statement is verifiable without anybody managing a signing key. SLSA supplies the provenance predicate — the specific claim about how the artifact was built — and the levels describing how much that claim can be trusted. SBOM data can travel as a separate attestation about the same subject.

Knowing this is mostly useful for reading other people’s documentation, where the terms are used interchangeably and are not.

Two honest observations, because SLSA discussion tends toward the aspirational.

Most organisations should target Build L2 and stop there for a while. On GitHub Actions, L2 is a workflow step. L3 requires restructuring builds into reusable workflows, which is a real refactor with real disruption, and it defends against an attacker who has already compromised your build steps — which is a threat worth defending against after the more common ones.

The Source track is undervalued. Most of it is repository configuration that a well-run repository already has, and it addresses the threat that is by far the most common in practice: an unreviewed or unattributable change reaching the branch that gets built. An organisation at Source L3 with Build L1 is in a defensible position; the reverse is unusual and less useful.

The general principle: levels are a description, not a target. The question worth asking is not “how do we reach L3?” but “which of these threats applies to us, and what does closing it cost?” The level follows from the answer rather than driving it.

Saying “SLSA Level 3” without a track. Two tracks, different level counts, different meanings.

Using the old four-level model. The single-ladder model predates the current specification. Material describing “SLSA 4” is stale.

Believing a level implies the artifact is safe. It describes the process.

Generating provenance and never verifying it. The level is met and the security benefit is not.

Attesting from the calling workflow. For Build L3 the reusable workflow must generate the attestation, or the isolation the level requires is not there.

Treating levels as a compliance ladder to climb for its own sake. The value is in what each level lets a consumer conclude. If nobody consumes your artifacts, L1 with real verification of your inputs may be worth more than L3 on your outputs.

Ignoring the Source track. For most organisations it is the cheaper half, because it is repository configuration they may already have.

A level claim is only useful if it is accurate, and accuracy requires writing down which requirements you meet and how you know. The exercise takes an hour and is worth doing before anybody says a number out loud.

For the Build track, per artifact you publish:

  • Is provenance generated? If not, L0.
  • Is it generated by the platform, or by a step in your workflow? A step you wrote generating a provenance file is not the same as the platform generating it, and the difference is exactly the L1 to L2 boundary.
  • Is it signed, and by whom? Signed by the platform is L2. Signed by a key your workflow holds is not, because a compromised build step can use that key.
  • Can a build step reach the signing material or influence another run? If yes, not L3.

For the Source track, per repository:

  • Is force-pushing blocked and are deletions restricted on the branches you build from?
  • Are those controls defined at the organisation, where a repository admin cannot relax them?
  • Are two reviewers required on protected branches?

Where the answer is “for most repositories”, the honest claim is about the ones where it is true rather than about the organisation. A per-repository position is more useful than an aggregate one anyway, because consumers care about the specific artifact they are installing.

SLSA is a shared vocabulary for describing how much a claim about a build can be trusted. Each level answers “what would an attacker have to do to make this provenance lie?” — and the answer is the whole content of the level.

  • The current specification uses tracks, each with its own levels; the old single four-level model is stale
  • The Build track has L0 to L3; the Source track, new in v1.2, has L0 to L4
  • Build L1 provenance may be unsigned and defends only against mistakes
  • Build L2 requires the hosted platform to generate and sign the provenance
  • Build L3 requires a hardened platform where build steps cannot influence signing or reach secrets
  • On GitHub, Build L3 needs the build in a reusable workflow that generates the attestations itself
  • The Source track maps onto branch protection, rulesets and required reviews
  • A level describes the build process, never the safety of the artifact
  • Verification by consumers is not a level requirement and is where the security benefit is

Mostly assessment. Use a repository that builds and publishes something.

  1. Read the current SLSA specification’s Build track requirements. Predict: which level does your pipeline meet today?

  2. Check whether your build produces provenance at all. If not, you are at L0 regardless of everything else.

  3. Add actions/attest-build-provenance to a GitHub-hosted build. Predict: which level does that reach, and why is it not L3?

  4. Move the build steps into a reusable workflow that generates the attestation. Verify the resulting provenance and read which workflow it names as the builder.

  5. Assess the Source track. Is branch history immutable? Are rulesets enforced at the organisation? Are two reviewers required? Predict: which Source level do you meet?

  6. Ask whether anything you consume publishes provenance, and whether you verify it. Predict: the answer for most organisations is “some” and “no”.

  7. Write down your actual position, per track, with the evidence. That document is what a level claim should be backed by.

GitHub Actions Security ChecklistToken permissions, fork pull requests, script injection and supply chain — with the attack each item prevents.

The repository security templates — secrets management and least-privilege token guides — are in the Professional Toolkit.