An SLSA level is not a badge, it is a boundary line. "We're at Build Level 2" sounds like an achievement; the real information sits in what that sentence leaves unsaid — you are still exposed to tampering that happens during the build. Teams that read levels as badges are living with a door they believe is closed but isn't.
This post is not about how to set SLSA up. I covered the setup side step by step in SLSA provenance and GitHub Artifact Attestations setup. The question here is a different one: what does the level number in your hands promise, what does it not promise, and which target is right for your environment?
First, the version trap: which SLSA are we talking about?
I nearly opened this post by trusting my own memory — "SLSA v1.0, four Build levels." I'm glad I checked. Open slsa.dev/spec/v1.1/levels today and the top of the page tells you the specification is Retired and points you to v1.2. So even v1.1, approved back in April 2025, is no longer current.
More than that, v1.2 also changed the page structure: the old levels page is gone, and the level definitions now live on the build-track-basics page. If you clicked a /levels link in an old blog post and got a 404, that's why.
The genuinely interesting part is this: GitHub's Artifact Attestations documentation still references SLSA v1.0 and describes levels against that version. This isn't an error — the meaning of the Build track hasn't changed since v1.0, so what it says holds. But it illustrates something: if your compliance document says "SLSA v1.0 Build L2" while your supply chain team is reading the v1.2 text, you are speaking the same number while reading different documents. A level claim that doesn't state which version it was measured against is half a claim.
The Build track: four levels, two different adversaries
The Build track runs from L0 to L3. There is no L4 — it existed in the old SLSA v0.1 and was removed with v1. I still come across slide decks saying "we're targeting SLSA Level 4"; that target does not exist in today's specification.
Instead of memorising the levels, read them with one question: which adversary does this level keep out?
Build L0 — no guarantees. In the specification's words, "L0 represents the lack of SLSA". No requirements. Let's be honest, most internal tooling lives here.
Build L1 — provenance exists. The build platform automatically generates provenance describing how the artifact was built, and you distribute it to consumers. What you gain: you can catch mistakes, such as building from a commit that is not present in the upstream repo. What you don't gain is written out plainly — provenance may be incomplete and/or unsigned at L1. So L1 is a paper wall against anyone acting in bad faith. It is process hygiene, not a security control.
Build L2 — hosted build platform. Now the platform itself generates and signs the provenance, and the consumer can validate that signature — if they do; I'll come to why that's a large "if" in a later section. The door you close: tampering after the build. You cannot alter the artifact without breaking the signature. The door you leave open: everything that happens during the build. Put differently, a poisoned compilation step will hand you a perfectly signed provenance — and that signature proves not that the statement is true, but that it was genuinely made on that platform.
Build L3 — hardened builds. On top of L2, the platform must implement controls that prevent runs from influencing one another. The door you close: tampering during the build by insider threats, compromised credentials, or other tenants.
There is a very common misreading here, and I got it wrong myself while drafting this post. L3's secret requirement is not about your secrets. The specification is explicit: a build must not be able to access "any secrets of the build platform, such as the provenance signing key," because that would compromise the authenticity of the provenance. What is protected is the platform's own key, not your deploy credentials or API keys. The spec draws the boundary explicitly too: Build L3 "is limited to ensuring that a well-intentioned build runs securely" and does not require the platform to stop a producer from performing a risky or insecure build. Your L3 badge does not fix bad secret hygiene inside your own pipeline.
The difference fits in a single sentence. Describing L2, the specification says forging the provenance requires an explicit attack "though this may be easy to perform"; for L3 it sets the bar at "exploiting a vulnerability beyond most adversaries' capabilities." Moving from L2 to L3 is moving from "they can if they try" to "they can't even if they try." The number goes up by one; the threat model changes completely.
An uncertified confession: my own pipeline isn't even L1
Explaining the theory is easy. Looking at your own setup is slightly more uncomfortable.
This blog's repository has 18 GitHub Actions workflow files. Ten of them run only on [self-hosted, ...] runners on my own VPS, seven only on ubuntu-latest, and one (failure-alert.yml) uses both. While preparing this post I got curious and searched the repository for any workflow requesting attestations or id-token permissions. There are none.
So this blog's content pipeline is, by its own yardstick, at Build L0. A pipeline that publishes posts about supply chain security while generating no provenance whatsoever for its own output is, I'll admit, a little funny. I won't dress it up as a vulnerability either; nobody but me consumes this blog's output. But how many teams say "nobody consumes it" about their internal tooling too — that's a different question.
But the confession has a second half, and that's where the real point is: in my case the right move is not to sprint for L3. Providing the isolation guarantees L3 asks for on a self-hosted runner — runs that cannot influence one another, a platform signing key that build steps cannot read — is serious work. The spec also leaves a subtle door open here: the "Isolated" requirement does not prohibit a build from calling out to a remote execution service or a self-hosted runner outside the build platform's trust boundary. So "we run on GitHub" is not by itself an isolation claim; where the work actually executes matters. I covered part of that in self-hosted CI runner security. For a one-person blog pipeline, climbing to L1 and starting to produce provenance is worth far more than dreaming about L3 and doing nothing.
In your environment the question is probably the same: one step up, or no step at all?
Which level does your hosted platform actually give you?
A concrete example: GitHub Artifact Attestations. The documentation is unambiguous — "Artifact attestations by itself provides SLSA v1.0 Build Level 2." So out of the box you get L2. L3 comes with an extra condition: you need reusable workflows that isolate the build process from the calling workflow.
The subtlety here is where most teams slip. Adding an attest-build-provenance step to your workflow does not make you L3. What determines the level is whether your build steps are isolated from the environment they themselves define. Doing the build and producing the attestation in the same workflow file means making an attacker's already-controlled process issue a signed document about itself.
There's one more thing: the hosted platform gives L2 to you, but says nothing about your dependencies. Your artifact's provenance does not cover how the third-party package you pulled in was built. SLSA proposes handling this through recursive verification, but in practice most of the ecosystem still produces no provenance at all.
v1.2's quiet revolution: the Source track
The most important change in v1.2 isn't an added level, it's an added track: the Source track. Its purpose is to give producers and consumers increasing levels of trust in the source code they produce and consume. The threat model was updated accordingly.
The Source track uses a different scale from the Build track, and it has four steps:
- Source L1 — Version controlled: the source is stored and managed through a modern version control system.
- Source L2 — History & Provenance: branch history is continuous, immutable and retained, and the SCS issues Source Provenance Attestations for each new source revision.
- Source L3 — Continuous technical controls: the SCS is configured to enforce the organisation's technical controls for specific named references in the repository.
- Source L4 — Two-party review: changes in protected branches MUST be agreed to by two or more trusted persons prior to submission.
Here's the curious part: there is no L4 in the Build track, but there is one in the Source track. Anyone trying to compress both into a single "our SLSA level is N" sentence is going to get a headache. The correct sentence has two parts: "Build L2, Source L1."
And let's be honest — the two-party review Source L4 asks for is by definition impossible on a solo project. That isn't a shortcoming, it's a fact. SLSA's levels measure the shape of your organisation too, not just your tooling.
Producing provenance means nothing on its own
If one sentence from this post sticks, let it be this one. The specification's verification page puts it exactly like this: "provenance doesn't do anything unless somebody inspects it."
Every attestation you generate is a decorative log line until someone looks at it. SLSA calls that inspection verification, and it has three components: verifying the signature and the builder's identity against a trusted root; checking that the values inside the provenance match your expectations — particularly buildType and externalParameters, rejecting parameters you don't recognise; and optionally verifying dependencies recursively.
The security boundary is in the second item. "Expectations are known provenance values that indicate the corresponding artifact is authentic." If you haven't defined expectations, signature verification only tells you "someone really did sign this document"; it does not tell you "the right repo, the right workflow, the right branch." A pipeline that produces attestations but performs no expectation check at deploy time is a pipeline writing letters to itself.
There's a cost to applying this in production, too: the first time you turn expectation checking on, your deploy breaks. It should break — that break reveals a path through your pipeline that had never been questioned. But don't switch it to enforce mode on a Friday evening.
Where verification belongs
Where the expectation check runs makes more difference than your level does. In practice there are three places, and each protects something different.
At the publish gate (CI). You verify your own provenance before pushing the artifact to the registry. Cheapest place, fastest feedback. The weakness is obvious: whoever compromises the pipeline has compromised the gate too. Verifying your own signature to yourself is a consistency check more than a security control.
At the admission gate (registry or admission controller). Verification happens at the edge of the cluster that will run the artifact — an image that is unsigned or fails expectations never gets in. This is where the real gain is, because the verifying party is not the producing party. I described the mechanics of that rejection flow in Signature chain with Cosign and Sigstore; on the SLSA side the only thing that changes is that the field you inspect is the content of the provenance rather than the mere presence of a signature.
At runtime. It looks appealing and is rarely the right place. Saying "I shouldn't have pulled this" after a pod is already up is reporting the incident, not preventing it.
At scale those three placements aren't enough: evaluating the full provenance chain and transitive dependencies for every image at every admission gate is expensive. SLSA's own answer is the Verification Summary Attestation (VSA). The idea is simple: a party you trust does the hard work once and publishes the result as a signed summary, so a consumer can decide without needing access to all of the attestations about the artifact or all of its transitive dependencies. You delegate the complex policy decision to a trusted party. In an organisation with hundreds of services, this is usually what keeps verification alive — not re-evaluating policy from scratch in every cluster.
Plan two operational things from the start. First, the failure mode: what happens when the verification service or the transparency log is unreachable? Fail-closed is safe but puts an external dependency on your deploy path; fail-open silently cancels the control at the first outage. Both are defensible; what isn't defensible is making that decision by accident. Second, visibility: publish the count of rejected artifacts as a metric. If that number is zero for months there are two possibilities — either your supply chain is spotless, or your control never runs. You want to know which.
What SLSA does not cover
The healthy way to use a framework is to know its edges. SLSA's threat model states what it does not cover with unusual clarity:
- A malicious producer. If the maintainer deliberately plants a backdoor: "This kind of attack cannot be directly mitigated through SLSA controls." Provenance will faithfully document that backdoor.
- Collusion and social engineering. Deceiving a reviewer, or two people agreeing: not currently addressed by SLSA.
- Typosquatting. It does not stop you from picking the wrong package.
- Insecure usage. Running the right artifact with the wrong configuration is not SLSA's subject.
- Availability. Deletion or de-listing of a package: "SLSA does not currently address availability threats."
- Runtime dependencies. The threat model does not explicitly model them.
This list is a good antidote to management decks that treat SLSA as an entire security programme. SLSA produces a verifiable claim about how an artifact was built. It makes no claim that the code is good.
The compliance angle: where do the numbers go?
For teams in Türkiye this is usually a distant topic, but for anyone selling software to a US federal buyer it is concrete. CISA's Secure Software Development Attestation Form is based on NIST's SSDF practices and requires the producer to attest that it has adopted secure development practices.
But let me apply this post's own warning to my own compliance section: the ground shifted here too. EO 14306, effective June 2025, amended the relevant provisions of EO 14144 and removed both the requirement that attestations be machine-readable and the directive for centralised validation by CISA. The form is still published and agencies can still ask for it; what changed is the central enforcement mechanism. The same order also called for SSDF to be updated — which is exactly why the Rev. 1 draft of SP 800-218 appeared in December 2025. Confirm the contractual side with your own legal team, not with posts written in 2024.
SSDF itself — NIST SP 800-218, Secure Software Development Framework (SSDF) Version 1.1, February 2022 — names provenance data as a practice in its own right; the PS.3 family covers archiving integrity verification information and provenance data for each software release. Worth noting: a Rev. 1 draft of SP 800-218 (SSDF 1.2) has been published, so the version ground is shifting here too.
In short, your SLSA level isn't a checkbox on the compliance form — but whether you hold machine-verifiable evidence while filling those boxes determines how hard the job is.
A decision framework
Work through these questions in order when setting your target level:
- Does anyone besides you consume your artifact? If not, L1 is plenty; it catches mistakes and costs almost nothing.
- Is your build platform hosted, or your own machine? On a hosted platform, L2 is mostly a configuration matter. On your own runner the signing half of L2 is easy; the isolation half of L3 is the actual work.
- Do your build steps define their own environment? If so, you cannot claim L3. Move to reusable/isolated builds first.
- Is there an expectation check on the deploy side? If not, your practical security gain is close to zero whatever your level. Put this item ahead of any level upgrade.
- Where are you on the source side? Without protected branches and a review rule, Build L3 is the open window next to a locked door.
- Which version are you measuring against? Write it into your claim: "SLSA v1.2 Build L2."
The fourth item is the most frequently skipped and the cheapest. If it were me, I'd order it like this: verification and expectation checks first, then the climb from L1 to L2, and L3 hardening last. Most teams do the exact opposite — they plan the most expensive step first and never take the cheapest one.
Closing
The real value of SLSA levels is that they move the security conversation from an unanswerable question like "are we secure enough" to an answerable one like "which adversary have we kept out." The number isn't a goal, it's a translation device: it turns a technical control into a sentence about threat that management can follow too.
That's why the most useful exercise isn't climbing a level, it's naming your current one honestly. Looking at my own pipeline I saw L0, and writing that down taught me more than planning the next level would have. Ask your own build the same question: for the artifact produced today, what can you prove while trusting nothing beyond the machine that produced it?
If the answer is "nothing," the right starting point isn't L3. The right starting point is generating the first provenance file and putting the first expectation check on your deploy step.
Top comments (0)