A few years ago, CI/CD pipelines were considered safe by default. Nobody really asked whether the compiled code matched exactly the versioned source code. Today, with attacks such as SolarWinds, we know that every link in the chain can be compromised: from the initial commit to the final artifact.
SLSA (Supply-chain Levels for Software Artifacts, pronounced "salsa") offers a structured answer to this problem. The framework defines progressive requirements to secure the whole software lifecycle.
The framework is backed by the OpenSSF (Open Source Security Foundation) and is aimed at DevOps, systems and security teams. SLSA does not dictate specific tools: it defines principles that apply to every CI/CD pipeline, whatever the technology used.
What you will learn
This page takes you from the observation that a chain can be compromised at every link to a gradual adoption, with pipelines to write and levels to aim for. By the end, you will be able to:
- Place the nine threats (A to I) of the SLSA v1.2 model and spot the ones the framework covers and the ones it leaves aside;
- Tell apart the Source Track (L1 to L4, new in v1.2) from the Build Track (L0 to L3), and say what each level guarantees;
- Explain what a provenance is and why it proves how an artifact was built;
- Generate a signed provenance with GitHub Artifact Attestations, then verify it before a deployment;
- Choose the level your CI/CD platform can reach, and plan a realistic maturity path.
Why has software supply chain security become critical?
Modern applications are no longer monolithic blocks written from A to Z by a single team. They rely on many external elements: open source libraries, container images, build tools, automated scripts. All these components make up what is called the software supply chain.
Each link in this chain is a potential entry point for an attacker:
- Source code: Git repositories hold the code, branches, commits and tags. An attacker who gains access to the repository can change the code without anyone noticing.
- CI/CD pipelines: GitHub Actions, GitLab CI and Jenkins run automated scripts. A compromised pipeline can inject malicious code during compilation.
- Secrets: API tokens, SSH keys, signing certificates. Stealing them allows an attacker to publish malicious versions that look legitimate.
- Artifacts: container images, binaries, npm/pip/Maven packages. Once published, they are downloaded by thousands of users.
The main problem: if a pipeline is compromised, software can be modified without touching the Git repository. The source code stays intact, but the distributed artifact contains malicious code. That is exactly what happened with SolarWinds.
SLSA introduces control and traceability mechanisms to detect such tampering. The central idea: stop trusting blindly and require verifiable evidence at every step.
The diagram below sets the vocabulary used throughout this page: a producer writes the source, the build compiles it while integrating dependencies, then distribution delivers the artifact to the consumer. The dotted link is a reminder that a dependency is itself a distributed package.
Which threats can SLSA counter?
To understand the value of SLSA, let us look at the real attacks it can detect or prevent. The official threat model (SLSA v1.2) splits the chain into nine threats, labeled A to I, spread over four stages: the source, the build, the distribution and the usage.
This diagram places each threat where it strikes. SLSA does not claim to cover them all: it is very effective from the source through the build to the distribution (threats B to G, the source through the Source Track and its two-person review), but acknowledges that it does not directly address the malicious producer (A), package selection (H) or final usage (I). This is the framework's honesty, not a hidden gap.
Threats to the source (A, B, C)
These attacks target the code and the repository before any compilation.
| Threat | What the attacker does | How SLSA helps |
|---|---|---|
| (A) Malicious producer | A trusted maintainer deliberately publishes a booby-trapped version | Not directly in scope: the provenance at least traces the origin and the author |
| (B) Source modification | Pushes code without going through review (direct push to main) | Source L3-L4: protected branches and two-person review |
| (C) Source manager abuse | An administrator bypasses the controls or compromises the SCM server | Source L3: technical controls recorded in signed attestations |
Real example: PHP (2021)
In March 2021, attackers compromised PHP's self-hosted Git server and injected two malicious commits into the main branch. Those commits added a backdoor to the PHP language itself. The maintainers detected the attack quickly thanks to their review process. It is a typical case of threat (C): compromise of the source manager.
With Source L3-L4, this attack would have been much harder: branch controls would have blocked the injection and the attestations would have exposed it.
Threats to the build (D, E, F)
These attacks target the compilation pipeline and the publication of the artifact.
| Threat | What the attacker does | How SLSA helps |
|---|---|---|
| (D) Unofficial build parameters | Runs the build from a fork or with unexpected parameters | The provenance reveals the real source; verification compares it with the expected source |
| (E) Build process compromise | Plants code in the build platform or steals the signing key | Build L3: build isolation and signing key unreachable by the build code |
| (F) Tampering at publication | Modifies the artifact (or its provenance) between the build and release | Build L2+: signed provenance; integrity check before promotion |
Real example: SolarWinds (2020)
The SolarWinds attack is the perfect example of threat (E). The attackers infiltrated SolarWinds' build system and altered the compilation process to inject malicious code into the updates of the Orion software. The source code was clean, but the distributed binaries contained a backdoor.
18,000 organizations installed the compromised update, including US government agencies.
With Build L3, this attack would have been detectable: build isolation would have prevented the injection, or at the very least the provenance would have revealed anomalies.
Threats to distribution (G)
Once published, the artifact travels through a distribution channel: a registry (npm, PyPI, Docker Hub), a mirror or a CDN. This link concentrates millions of downloads, which makes it a prime target.
| Threat | What the attacker does | How SLSA helps |
|---|---|---|
| (G) Distribution channel compromise | Replaces the package on the registry through an admin interface or an infrastructure compromise | Artifact signing and provenance verification on the consumer side, which detect any substitution |
The defense is not to trust the registry but to verify: a consumer that checks a package's signature and provenance immediately detects a substituted artifact, even when it is served by a legitimate mirror. That is the whole point of Cosign and of the automated verification described below.
Threats at usage time and on dependencies (H, I)
These attacks exploit the consumer's choice and use of the package. SLSA covers them poorly on its own, but its logic applies recursively to dependencies: a third-party component is itself an artifact that deserves its provenance.
| Threat | What the attacker does | How SLSA helps |
|---|---|---|
| (H) Bad package selection | Typosquatting (lodash vs 1odash) or dependency confusion (a name identical to an internal package) | Not directly in scope; provenance verification confirms the expected origin |
| (I) Insecure use | The package is misconfigured (default credentials, dangerous options) | Out of SLSA's scope: it is a matter of hardening on the consumer side |
Real example: event-stream (2018)
An attacker first earned the trust of the maintainer of the npm package
event-stream (about 2 million weekly downloads; the November 2018 sources give
1.5 to 2 million), then slipped malicious code into a transitive dependency
targeting Bitcoin wallets. It is threat (A) applied to a dependency:
proof that a project's security depends on that of its whole chain.
Typosquatting and dependency confusion attacks (threat H) are detailed
in attacks through package
managers.
Understanding the two SLSA tracks
SLSA organizes its requirements into two complementary tracks. Each track addresses a different part of the supply chain:
| Track | What it protects | Available levels |
|---|---|---|
| Source Track | The source code and its integrity | L1 → L4 |
| Build Track | How artifacts are built | L0 → L3 |
Why two tracks? Because securing only the build is not enough. If the source code itself is compromised (malicious commit, hijacked repository), even the best build pipeline will produce a dangerous artifact. Conversely, securing the source code without controlling the build leaves the door open to injections during compilation.
The two tracks work together to cover the whole cycle: the Source Track guarantees the integrity of the code upstream, the Build Track guarantees the integrity of the build downstream.
Source Track: securing the source code
The Source Track defines increasing levels of trust in source code management. It answers the question: can we prove that the source code used for the build is the one the team approved?
Here are the four levels of the Source Track, from the most basic to the most demanding:
| Level | Short name | What it means in practice |
|---|---|---|
| L1 | Version controlled | The code is in a versioning system (Git, etc.) |
| L2 | History & Provenance | The history is preserved and attestations are generated |
| L3 | Continuous Technical Controls | Automatic technical controls are enforced |
| L4 | Two-party review | Every change requires the approval of two people |
Source L1: the code is versioned
The first level may seem obvious, but it is fundamental. At this level, the source code must be stored and managed in a modern version control system such as Git, Mercurial or Subversion.
Why does it matter? Without versioning, it is impossible to know who changed what, when and why. Changes are invisible. With a versioning system, every change is recorded with a unique identifier (the commit hash), the author, the date and the commit message.
What you need to put in place:
- Use Git (or an equivalent) for all source code
- Never modify files directly on the production server
- Also version your deployment scripts and configurations
Who is this level for? Organizations that still manage some code in a non-standard way (files shared on a network drive, FTP, etc.). It is the essential first step towards SLSA.
Source L2: reliable history and source provenance
Level 2 adds guarantees on the integrity of the history. Having a history is no longer enough: you must be able to prove it has not been altered.
The problem it solves: in Git, it is technically possible to rewrite the history (force push, rebase, etc.). An attacker with access to the repository could modify old commits to hide their tracks. At level 2, the history must be continuous, immutable and retained.
What you get:
- The complete history of changes is preserved and cannot be rewritten
- The source control system generates source provenance attestations: signed documents that certify the origin of the code
- These attestations are tamper-resistant evidence
What you need to put in place:
- Enable protection of the main branches (forbid force push on
main) - Configure Git history retention
- Set up an attestation generation system (if your platform supports it)
Who is this level for? Every organization that produces software. It is the minimum level recommended for production applications.
Source L3: continuous technical controls
Level 3 introduces automatic enforcement of rules defined by the organization. It is no longer just "the history is preserved" but "controls are actively enforced and verifiable".
The problem it solves: an organization may have rules (mandatory review, no merge without green tests), but nothing proves they were followed. An administrator with the right permissions can bypass them. At level 3, the source control system (SCS) records the controls that were enforced in the attestations.
What you get:
- Branch policies are enforced technically (not merely documented)
- Provenance attestations include the proof of the controls applied
- Consumers of the code can verify that the controls were respected
What you need to put in place:
- Configure branch protection rules with strict enforcement
- Require tests to pass before merging
- Require at least one review approval
- Make sure your platform records these controls in the attestations
Who is this level for? Organizations that want to prove to their customers or partners that their development processes meet security standards.
Source L4: mandatory two-person review
Level 4, the most demanding, imposes a two-person review for every change to the code on protected branches.
The problem it solves: with a single reviewer, that person can be compromised (hijacked account, malicious insider, a lapse of attention). With two people, the probability of collusion or double compromise drops drastically.
What you get:
- Every change requires the approval of two distinct trusted people before it is merged
- Protection against unilateral changes, even by administrators
- Resistance to insider threats (a lone malicious developer can do nothing)
What you need to put in place:
- Configure branch rules to require at least 2 approvals
- Make sure the author of the code cannot be one of the approvers
- Set up processes to handle emergencies (hotfixes) while still respecting the four-eyes principle
Who is this level for? Organizations with high security requirements: critical software, sensitive infrastructure, strict regulatory compliance.
Build Track: securing the build
The Build Track defines increasing levels of trust in how artifacts are built. It answers the question: can we prove that this artifact was built from this source code, without modification?
The central notion of the Build Track is the provenance: a document that describes exactly how an artifact was produced. The higher the level, the more reliable the provenance and the harder it is to forge.
Here are the four levels of the Build Track:
| Level | Short name | What it means in practice |
|---|---|---|
| L0 | No guarantees | No guarantee (local build, no traceability) |
| L1 | Provenance exists | A provenance is generated, but it can be forged |
| L2 | Hosted build platform | The provenance is signed by a hosted platform |
| L3 | Hardened builds | The build is isolated and protected against tampering |
Build L0: no guarantees
Level 0 means the absence of control. It is the starting point of many organizations that have not yet formalized their build chain.
What it means in practice:
- Builds can be run from a developer's workstation
- No provenance is generated
- It is impossible to know who built what, when, and from which code
Why is it a problem? A malicious developer (or one whose workstation is compromised) can publish an artifact containing malicious code. Nobody can verify that the artifact matches the source code.
Who does this level match? Exploratory development projects, prototypes, non-critical internal tools. This level is not acceptable for production software.
Build L1: the provenance exists
Level 1 is the entry point into SLSA. At this level, the build process generates a provenance: a document that describes how the artifact was built.
What you get:
- The build is run by a CI/CD pipeline (not on a local workstation)
- A provenance is generated automatically
- The provenance links the source code (commit) to the artifact
What the provenance contains:
- The identifier of the source commit (Git SHA)
- The origin repository
- The build timestamp
- The build tool used
Important limitation: at this level, the provenance can be forged. A malicious actor with access to the pipeline can modify the provenance to make it look as if the artifact came from another commit.
Who is this level for? Teams that want to gain the benefits of SLSA quickly without overhauling their infrastructure. It is a good starting point.
Build L2: hosted build platform
Level 2 adds a crucial layer of security: the provenance is generated and cryptographically signed by a hosted build platform.
The problem it solves: at level 1, anyone with access to the pipeline can generate a fake provenance. At level 2, only the build platform can sign the provenance with its private key. This signature proves authenticity.
What you get:
- The provenance is signed by the platform (GitHub, GitLab, Google Cloud Build, etc.)
- The build runs on dedicated infrastructure, not on a developer's workstation
- Consumers can verify the signature to ensure authenticity
What it protects against: tampering after the build. Once the artifact is built and the provenance signed, it becomes very hard to modify them without invalidating the signature.
What you need to put in place:
- Use a hosted CI/CD platform (GitHub Actions, GitLab CI, etc.)
- Configure signed provenance generation (depending on your platform's capabilities)
- Store the provenance with the artifact
Who is this level for? Teams that have migrated to a hosted platform and want a guarantee of authenticity. It is the minimum level recommended for critical applications.
Build L3: hardened builds
Level 3, the highest of the Build Track, offers strong protection against tampering during the build itself.
The problem it solves: at level 2, the build runs on a hosted platform, but that platform could be compromised. An attacker with access to the build infrastructure could modify the compilation process. At level 3, isolation measures prevent these attacks.
What you get:
- Full isolation between builds: one build cannot influence another
- Unreachable signing secrets: the keys used to sign the provenance are never accessible to the build code
- Complete auditability: every action is logged and verifiable
What it protects against:
- Insider threats (a malicious employee with access to the infrastructure)
- Compromised credentials (even with a stolen token, the attacker cannot forge a valid provenance)
- Cross-tenant attacks (a malicious customer of the platform cannot compromise another customer's builds)
Platforms reaching Build L3:
- GitHub Actions (native Artifact Attestations, inside a reusable workflow that generates the attestation)
- Google Cloud Build
Who is this level for? It is the recommended target level for most software releases. If you publish artifacts used by others (libraries, Docker images, packages), aim for Build L3.
Provenance: the heart of the SLSA system
Now that you understand the two tracks, let us talk about the provenance, the central concept that makes the whole SLSA system work.
The provenance is a structured piece of metadata that describes precisely how an artifact was produced. Think of it as a birth certificate for your software: it states its origin, the circumstances of its creation, and who was present.
What a provenance contains:
- Code origin: the exact Git commit identifier (SHA), the branch, the tag, the repository URL
- Build tool: Make, Maven, npm, Docker, Gradle, and their versions
- Execution environment: operating system, version, CI runner identifier, precise timestamp
- Build system identity: which platform generated the provenance, with which signing key
Why is it revolutionary? Before SLSA, a binary or a Docker image was a black box. It was impossible to know for certain where it came from. With the provenance, any consumer can verify:
- Who built the artifact (which CI/CD platform)
- Where the build ran (which runner, which infrastructure)
- When it was produced (precise timestamp)
- From what (the exact commit of the source code)
- How (the commands, tools and versions used)
The provenance thus becomes the cryptographic proof of the integrity of the build process. If someone modifies the artifact afterwards, the provenance signature will no longer match.
Implementing SLSA: a step-by-step guide
Let us move on to practice. How do you implement SLSA in your organization? The recommended approach is progressive: start with an audit, then build up maturity step by step.
Step 1: Audit your existing pipelines
Before changing anything, take stock. You need to understand how your software is currently built and published.
# List all your CI/CD pipelinesfind .github/workflows -name "*.yml" -type fls .gitlab-ci.yml 2>/dev/null
# Look for potentially manual buildsgrep -r "docker build" . --include="*.sh"grep -r "npm publish" . --include="*.sh"grep -r "mvn deploy" . --include="*.sh"Questions to ask yourself during the audit:
- How many pipelines generate published artifacts (Docker images, npm packages, binaries)?
- Which ones are critical for your business or your customers?
- Are there manual steps in the release process?
- Are your artifacts signed? If so, where are the keys stored?
- Who has access to the pipeline secrets?
Document your findings. This audit will be the basis for prioritizing improvements.
Step 2: Fully automate the builds
Automation is the prerequisite for everything else. No manual intervention should be possible on the critical path from build to publication.
Goal: every published build must go through a CI/CD pipeline, without exception.
name: Build and publishon: push: branches: [main] tags: ['v*']
# Principle of least privilege: minimal permissions by defaultpermissions: contents: read
jobs: build: # Always use a fixed runner version, never 'latest' runs-on: ubuntu-24.04 steps: - name: Checkout code # Always pin actions by SHA, not by tag uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build application run: make build
- name: Run tests run: make test
- name: Build Docker image run: docker build -t myapp:${{ github.sha }} .stages: - build - test - publish
build: stage: build script: - make build artifacts: paths: - dist/
test: stage: test script: - make test
publish: stage: publish script: - docker build -t myapp:$CI_COMMIT_SHA . only: - main - tagsCheck: after this step, nobody should be able to publish an artifact without going through the pipeline.
Step 3: Generate the provenance (Build L2, then L3)
If you use GitHub Actions, you reach Build L2 by default with the
Artifact
Attestations
built into the platform. For Build L3, run the build in a reusable
workflow that itself generates the attestation: it isolates the build from the
calling workflow, and the permissions are set in both workflows (GitHub
procedure).
The actions/attest-build-provenance action produces a keyless signed
provenance through OIDC and Sigstore, and attaches it to your artifact. Nothing
to install, nothing to host.
The workflow below builds the image and generates the attestation in the same job: it reaches Build L2. To aim for Build L3, move these steps into a reusable workflow called by this one.
name: Release with SLSA provenance
on: push: tags: ['v*']
# Principle of least privilege: minimal permissions by defaultpermissions: contents: read
jobs: build: # Always use a fixed runner version, never 'latest' runs-on: ubuntu-24.04 permissions: contents: read packages: write # Push the image to GHCR id-token: write # Keyless signing via OIDC attestations: write # Attach the attestation to the artifact steps: # Always pin actions by SHA, not by tag - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Login GHCR run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Build image run: docker build -t ghcr.io/${{ github.repository }}:build .
- name: Push image and capture digest id: push run: | # Push the image and retrieve the immutable digest docker push ghcr.io/${{ github.repository }}:build DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/${{ github.repository }}:build | cut -d'@' -f2) echo "digest=$DIGEST" >> $GITHUB_OUTPUT # From here on, ALWAYS reference the image by its digest, not by tag
- name: Generate and attach the SLSA provenance uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1 with: subject-name: ghcr.io/${{ github.repository }} # Reference by digest (immutable), never by tag subject-digest: ${{ steps.push.outputs.digest }} push-to-registry: trueWhat this workflow does:
- Logs in to GHCR, builds and pushes the image
- Captures the immutable digest returned by the registry, the only reference used afterwards
- Generates a keyless signed provenance through OIDC and pushes it to the registry, next to the image
Step 4: Sign your artifacts with Cosign
On top of the SLSA provenance, sign your images with Cosign. Cosign allows keyless signing (no key management) thanks to OIDC authentication.
# In your CI/CD pipeline# The signature automatically uses the runner's OIDC identitycosign sign --yes ghcr.io/user/myapp@sha256:abc123...Why sign in addition to the provenance? The Cosign signature adds an extra layer of verification. It binds the artifact to the identity of the pipeline that built it (through the OIDC token). It is defense in depth.
Step 5: Verify before every deployment
The diagram below shows the SLSA verification flow on the consumer side, to be read from left to right: the build publishes a provenance next to the package, and both go through verification before any use.
Its elements read as follows:
- Build (left column): several build systems produce artifacts. Each one generates its own provenance.
- Provenance (in the package ecosystem): a signed document attesting the origin and the build process.
- Package (next to the provenance): the artifact distributed through the package ecosystem.
- Requirements (at the bottom): the criteria defined by the consumer (e.g. "must come from GitHub Actions", "must be signed").
- Automatic verification (highlighted element): the process that compares the provenance with the requirements before allowing use.
The consumer never trusts a package blindly. They require a valid provenance and automatically verify that it matches their expectations.
Generating provenance is pointless if nobody verifies it. Add a mandatory verification step before any deployment.
# Verify the Cosign signature# This command fails if the signature is invalid or missingcosign verify ghcr.io/user/myapp@sha256:abc123... \ --certificate-identity-regexp="^https://github.com/user/myapp" \ --certificate-oidc-issuer=https://token.actions.githubusercontent.com
# Verify the provenance produced by Artifact Attestations# This command fails if the provenance does not match expectationsgh attestation verify oci://ghcr.io/user/myapp@sha256:abc123... \ --repo user/myapp
# For an artifact produced by slsa-github-generator, the tool remains slsa-verifierslsa-verifier verify-image ghcr.io/user/myapp@sha256:abc123... \ --source-uri github.com/user/myapp \ --source-tag v1.0.0The two commands are not interchangeable: the producer decides the consumer's tool. Migrating to Artifact Attestations therefore changes the verification command your users will have to run, and that needs to be announced.
Integration in Kubernetes: you can use admission controllers such as Kyverno or Sigstore Policy Controller to automatically block the deployment of unsigned images or images without a valid provenance. The complete implementation, from verification in CI to the Kyverno policy, is detailed in From SLSA provenance to decision: blocking non-compliant artifacts.
Which SLSA level on each CI/CD platform?
Not every CI/CD platform can reach the same SLSA levels. Here is a summary based on each platform's official documentation.
| Platform | Native Build Track | Status | Source |
|---|---|---|---|
| GitHub Actions | L2 (L3 with a reusable workflow) | Production (Artifact Attestations) | GitHub Blog |
| Google Cloud Build | L3 | Production | Google Cloud Docs |
| GitLab CI | L2 | Production; L3 in beta (testing) | GitLab Docs |
| Jenkins | L1 | Proof-of-concept | Jenkins Plugin |
This table covers the Build Track, the only one that platforms self-certify. The Source Track, for its part, does not depend on the build tool but on the configuration of your repository: protected branches, mandatory review, immutable history. To date, neither GitHub nor GitLab publishes an official Source Track self-assessment; you reach it by hardening your source controls, detailed in the guide on source code governance.
Details of the sources:
-
GitHub Actions: the official GitHub Blog explicitly announces "reach SLSA Level 3" with Artifact Attestations, which are the recommended route today. The slsa-github-generator project, documented on slsa.dev, remains functional but is no longer actively maintained.
-
Google Cloud Build: the official documentation states "Cloud Build features meet the requirements of SLSA level 3". See also the slsa.dev article on GCB.
-
GitLab CI: the official documentation states a "SLSA level 2 compliant" provenance, signed by the GitLab Runner (so also Level 1). Level 3 is documented but in testing, not for production.
-
Jenkins: the SLSA plugin and the generator on GitHub are "proof-of-concept". Jenkins offers no native build isolation.
What if your platform tops out on the Build Track?
If you are on Jenkins, or if you want to go beyond GitLab's native Build L2, you can strengthen your posture in other ways:
- Harden the Source Track: protected branches and mandatory review bring you closer to the Source L3-L4 requirements, independently of the Build Track.
- Add Cosign signatures: sign your artifacts independently of the platform.
- Use third-party tools: Sigstore, Cosign and equivalent solutions fill the gaps where the platform provides nothing natively.
- Consider a migration: if the criticality of your applications requires it, GitHub Actions (with a reusable workflow) and Google Cloud Build offer Build L3.
Adopting SLSA gradually: a roadmap
SLSA is a marathon, not a sprint. Trying to reach L3 everywhere in a week is a recipe for failure. Here is a realistic approach spread over several months.
Phase 1: Quick wins (weeks 1-4)
Goal: lay the foundations without upsetting what already exists.
- Audit all pipelines and document the current state
- Enable branch protection rules on all critical repositories
- Require at least one review before merging
- Remove manual builds (no more local
docker buildfor releases)
Level reached: Source L2, Build L1
Phase 2: Strengthening (months 2-3)
Goal: add provenance and signatures.
- Implement Artifact Attestations on the pilot projects
- Add Cosign signing to Docker images
- Document the process for the other teams
- Set up tracking dashboards (% of artifacts with provenance)
Level reached: Source L2, Build L2-L3
Phase 3: Consolidation (months 4-6)
Goal: generalize and automate verification.
- Roll out on all critical projects
- Implement automatic verification before deployment
- Have the attestation generated by a reusable workflow to isolate the build from the calling workflow (condition for Build L3 on GitHub)
- Require two reviewers on the most sensitive repositories (Source L4)
- Train all the teams
Level reached: Source L3-L4, Build L3
Metrics to track
To steer your progress, track these indicators:
- % of automated pipelines: target 100%
- % of artifacts with provenance: target 100% of releases
- % of signed artifacts: target 100% of Docker images
- % of repositories with branch protection: target 100%
- Average review time: monitor it to avoid bottlenecks
Limits of SLSA and adoption challenges
Let us be honest: adopting SLSA takes a significant investment. Here are the challenges you will meet and how to approach them.
| Challenge | What it involves | How to overcome it |
|---|---|---|
| Provenance generation | Understanding GitHub Actions workflows, OIDC permissions, the in-toto format | Start with a simple pilot project, document every step |
| Keyless signing | Mastering Sigstore, Fulcio (CA), Rekor (transparency log) | Learn Cosign first, then go deeper into the ecosystem |
| Automated verification | Configuring gh attestation verify (or slsa-verifier) and a K8s admission controller | Train one reference person per team |
| Team training | 1 to 2 weeks to become autonomous | Plan dedicated time, not "on top of everything else" |
| Pipeline overhaul | 1 to 3 months depending on complexity | Migrate project by project, not all at once |
| Perceived slowdown | Reviews and verifications add time | Communicate on the value: it is an investment, not a cost |
Symptoms of poor adoption:
- Developers bypass the system (local builds "in an emergency")
- Reviews are done without actually reading the code (rubber-stamp approval)
- The provenance is generated but never verified by anyone
- The metrics look good on paper, but real security does not improve
The right approach: SLSA must deliver visible value.
- Fast detection when something goes wrong (alerts on invalid provenance)
- Increased trust from customers and partners (verifiable proof)
- Compliance with regulations (NIS2, Cyber Resilience Act, SOC 2)
- Less stress during an incident (complete traceability for the post-mortem analysis)
SOCLE requirements covered
SLSA is not just a theoretical framework: its levels translate into requirements structured to be auditable. Putting this guide into practice means satisfying several requirements of the SOCLE framework (Sécurité de la Chaîne Logicielle, software supply chain security), each with an associated robustness level (R1 fundamental, R2 reinforced, R3 sovereign). Here is the mapping, from build to admission:
- SOCLE-INT-GEN-6 (in French) (R2): the build runs on a hosted, traced platform that generates a provenance. This is exactly the Build L2 described above.
- SOCLE-REL-GEN-2 (in French) (R2): the in-toto provenance is generated, attached to the artifact and verifiable by consumers. This is the core of the Build Track.
- SOCLE-REL-GEN-4 (in French) (R3): for sensitive artifacts, the provenance becomes unforgeable thanks to the isolated build (Build L3). This is the target level for critical releases.
- SOCLE-DPL-GEN-4 (in French) (R2): at admission, you verify the provenance against an expected builder and source (allowlist), not just the presence of an attestation. This is the verification before deployment step described above.
Framework: SOCLE. This guide implements these requirements; it is not a promise of compliance.
Key points
These points sum up what the page has set out. Use them as landmarks to reread before deciding on a level to aim for or auditing a pipeline.
- A chain is compromised at every link: source, build, distribution. Attacks such as SolarWinds or event-stream (about 2 million weekly downloads at the time of its compromise) show it.
- The SLSA v1.2 threat model counts nine threats, A to I. It covers B to G well, but does not directly address the malicious producer (A), package selection (H) or final usage (I).
- The Source Track has four levels, L1 to L4, L4 being the two-person review (two-party review); it is new in v1.2.
- The Build Track goes from L0 to L3: from no guarantee to isolated builds, whose signing key stays unreachable by the build code.
- The provenance is the keystone: it proves how an artifact was built, and once signed from Build L2, it makes any later modification detectable.
- With GitHub Artifact Attestations, you reach Build L2 by default; Build L3 requires a reusable workflow that itself generates the attestation.
- An unverified provenance protects nothing: check it before every
deployment, with
gh attestation verifyorslsa-verifierdepending on the tool that produced it. - Climb gradually: Source L2 and Build L2 already cover most needs, L3 and L4 come next for sensitive artifacts.
Conclusion
SLSA offers a structured method to secure your whole software supply chain. By combining the Source Track (protecting the source code) and the Build Track (protecting the build), you can prove the integrity of your software end to end.
What to remember:
- Source Track (L1-L4): from simple versioning to mandatory two-person review
- Build Track (L0-L3): from no guarantee to isolated, signed builds
- The provenance is the keystone: it proves how each artifact was built
- Gradual adoption is the key: start with Source L2 + Build L2, then build up maturity
The concrete benefits:
- Traceability: you know exactly who built what, when, and how
- Detection: an invalid provenance triggers an immediate alert
- Trust: your customers can cryptographically verify the origin of your software
- Compliance: SLSA prepares you for NIS2, Cyber Resilience Act and SOC 2 requirements
Do not seek immediate perfection. Every level you reach improves your security posture. The most important thing is to get started.