DevSecOps

SLSA Framework Guide: Securing Your Build Pipeline

A practical guide to the SLSA (Supply chain Levels for Software Artifacts) framework—understanding the four integrity levels, build provenance, hermetic builds, generating SLSA provenance in GitHub Actions, and the Sigstore ecosystem.

January 1, 20268 min readShipSafer Team

The Software Supply Chain Problem

The SolarWinds attack in 2020 demonstrated that the build pipeline itself is a high-value attack target. By compromising the build environment, attackers were able to inject malicious code into signed, legitimate software updates—bypassing every runtime and deployment security control. The Codecov attack, the XZ Utils backdoor, and npm package hijacking incidents all follow the same pattern: compromise the supply chain, and every downstream consumer becomes a victim.

SLSA (Supply chain Levels for Software Artifacts, pronounced "salsa") is a security framework developed by Google and the Open Source Security Foundation (OpenSSF) that provides a graduated set of requirements for build integrity. SLSA does not prevent all supply chain attacks, but it makes certain attack classes significantly harder and provides consumers with verifiable evidence about how software was built.

The Four SLSA Levels

SLSA defines four levels of increasing rigor. Each level builds on the previous.

SLSA Level 1: Provenance Exists

Requirement: The build process generates provenance—a document describing how the artifact was built.

Provenance is a metadata file that answers:

  • What source code was built (repository URL, commit hash)
  • What build system was used (GitHub Actions, Jenkins, CircleCI)
  • What build command was run
  • When the build occurred
  • What artifact was produced (content hash)

Level 1 provenance does not need to be signed or verified—it just needs to exist. This is the baseline for auditability. If an artifact's provenance claims it was built from commit abc123 but the artifact's hash does not match what commit abc123 would produce, that is a red flag.

Level 1 prevents: accidental artifact confusion (deploying the wrong artifact), auditing gaps.

SLSA Level 2: Hosted Build Service with Signed Provenance

Requirements:

  • Build is performed by a hosted build service (not a developer's laptop)
  • Provenance is generated by the build service itself (not the build script that could be compromised)
  • Provenance is signed by the build service

Signed provenance provides a much stronger guarantee: the build service certifies, with a cryptographic signature, that the artifact was built from the stated source code. A developer who can modify the build script cannot forge a valid signature from the build service.

Level 2 prevents: builds run on developer machines where the environment is uncontrolled, unsigned provenance that could be tampered with.

SLSA Level 3: Hardened Build Service

Requirements:

  • The build service runs in an isolated environment per build
  • The build definition is hosted in source control
  • The build service itself is protected against tampering
  • Provenance is unforgeable (the build service generates it in a trusted context that the build steps cannot influence)

Level 3 raises the bar significantly: to forge provenance, an attacker must compromise the build service itself, not just the build script. This requires a much more sophisticated attack.

Level 3 prevents: a malicious build script forging its own provenance, cross-build contamination, builds that are not reproducible from source.

SLSA Level 4: Two-Person Review and Hermetic Builds

Requirements:

  • All source code changes are reviewed and approved by two authorized contributors
  • Builds are hermetic: they cannot access the network during build (all inputs are declared upfront)
  • Builds are reproducible: building from the same source produces bit-for-bit identical output

Level 4 is the most demanding. Hermetic builds require that every build dependency (compiler version, OS packages, build tools) is locked and fetched from a content-addressable cache, not downloaded from the internet at build time. This closes the attack where a malicious package maintainer pushes a new version during your build window.

Two-person review prevents insider attacks where a single developer could compromise the source code.

Most organizations target SLSA Level 2 or 3. Level 4's hermetic build requirement is extremely demanding for most ecosystems.

Build Provenance in Practice

SLSA provenance follows the in-toto Attestation Framework—a standard format for signed metadata about software artifacts.

A SLSA provenance attestation contains:

{
  "_type": "https://in-toto.io/Statement/v0.1",
  "predicateType": "https://slsa.dev/provenance/v0.2",
  "subject": [
    {
      "name": "myapp:1.2.3",
      "digest": {
        "sha256": "abc123def456..."
      }
    }
  ],
  "predicate": {
    "builder": {
      "id": "https://github.com/actions/runner"
    },
    "buildType": "https://github.com/slsa-framework/slsa-github-generator/...",
    "invocation": {
      "configSource": {
        "uri": "git+https://github.com/myorg/myrepo@refs/heads/main",
        "digest": {
          "sha1": "abc123..."
        },
        "entryPoint": ".github/workflows/release.yml"
      }
    },
    "buildConfig": {
      "steps": [...]
    },
    "metadata": {
      "buildStartedOn": "2025-01-01T00:00:00Z",
      "buildFinishedOn": "2025-01-01T00:05:00Z",
      "completeness": {
        "parameters": true,
        "environment": false,
        "materials": true
      }
    },
    "materials": [
      {
        "uri": "git+https://github.com/myorg/myrepo@refs/heads/main",
        "digest": {
          "sha1": "abc123..."
        }
      }
    ]
  }
}

Generating SLSA Provenance with GitHub Actions

The SLSA GitHub Generator project provides reusable GitHub Actions workflows that generate SLSA Level 3 provenance for common artifact types.

For Go Binaries

# .github/workflows/release.yml
name: Release
on:
  push:
    tags:
      - 'v*'

permissions:
  contents: write
  actions: read
  id-token: write  # Required for keyless signing

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      hashes: ${{ steps.hash.outputs.hashes }}

    steps:
      - uses: actions/checkout@v4

      - name: Build binary
        id: build
        run: |
          go build -o myapp ./cmd/myapp
          echo "binary=myapp" >> $GITHUB_OUTPUT

      - name: Generate hash
        id: hash
        run: |
          set -euo pipefail
          echo "hashes=$(sha256sum myapp | base64 -w0)" >> $GITHUB_OUTPUT

      - name: Upload binary
        uses: actions/upload-artifact@v4
        with:
          name: myapp
          path: myapp

  provenance:
    needs: [build]
    permissions:
      actions: read
      id-token: write
      contents: write

    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
    with:
      base64-subjects: ${{ needs.build.outputs.hashes }}
      upload-assets: true

This generates a provenance attestation (.intoto.jsonl file) and uploads it alongside the binary as a GitHub release asset.

For Container Images

  provenance:
    needs: [build]
    permissions:
      actions: read
      id-token: write
      packages: write

    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
    with:
      image: ghcr.io/${{ github.repository }}
      digest: ${{ needs.build.outputs.digest }}
    secrets:
      registry-username: ${{ github.actor }}
      registry-password: ${{ secrets.GITHUB_TOKEN }}

The Sigstore Ecosystem

Sigstore is the infrastructure that makes practical, keyless signing possible. It consists of three components:

Cosign: A tool for signing and verifying container images and other artifacts. Supports keyless signing via OIDC identity tokens (from GitHub Actions, Google Cloud, etc.).

Fulcio: A certificate authority that issues short-lived code-signing certificates tied to OIDC identities. Instead of managing long-lived signing keys, Sigstore issues a certificate valid for minutes that is tied to your GitHub Actions workflow identity. The certificate is recorded in the transparency log.

Rekor: An immutable transparency log that records all signing events. Anyone can query Rekor to verify that a signature was made at a specific time by a specific identity.

The keyless signing flow:

  1. Your CI pipeline runs and obtains a GitHub Actions OIDC token
  2. Cosign sends the OIDC token to Fulcio and receives a short-lived signing certificate
  3. Cosign signs the artifact with the certificate
  4. The signature and certificate are recorded in Rekor
  5. Cosign discards the certificate (no key management required)

To verify a signature:

  1. Cosign retrieves the signature from the OCI registry
  2. Cosign queries Rekor to verify the signing event was recorded
  3. Cosign verifies the certificate matches the expected OIDC identity
# Verify a container image signed with keyless SLSA
cosign verify \
  --certificate-identity-regexp "https://github.com/myorg/myrepo/.github/workflows/release.yml@refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  ghcr.io/myorg/myrepo:v1.2.3

# Verify SLSA provenance
slsa-verifier verify-image \
  --source-uri github.com/myorg/myrepo \
  --source-tag v1.2.3 \
  ghcr.io/myorg/myrepo:v1.2.3

Hermetic Builds: The Level 4 Challenge

Hermetic builds require that all build inputs are declared and no network access is allowed during the build. This is architecturally demanding because most build systems download dependencies at build time.

Approaches to achieve hermetic builds:

Bazel: Google's Bazel build system was designed for hermeticity. It has a sandboxed execution model that can restrict network access and enforces that all inputs are declared.

Nix: The Nix package manager builds packages in a pure, isolated environment. All dependencies are content-addressed and fetched before the build begins.

Vendor directories: The simplest approach for many ecosystems. Check all dependencies into the repository (go mod vendor, npm pack to a vendor directory). The build then reads from the local copy rather than the network.

# Go: vendor dependencies
go mod vendor
# Build uses vendor/ directory
go build -mod=vendor ./...

# Node.js: use npm ci with network disabled
# (requires package-lock.json to be committed)
npm ci --prefer-offline

The network restriction can be enforced at the CI level: GitHub Actions does not natively support network restriction during steps, but runners can be configured to route through a proxy that allows only pre-approved destinations (your artifact registry, no public package registries).

Consuming SLSA Provenance as a Downstream User

SLSA provides value not just for producers of software but for consumers who want to verify what they are deploying.

If a package you depend on provides SLSA provenance, verify it:

# Verify the SLSA provenance of a GitHub release
slsa-verifier verify-artifact \
  --provenance-path myapp.intoto.jsonl \
  --source-uri github.com/upstream/myapp \
  myapp-linux-amd64

For container images in Kubernetes environments, policy enforcement tools (Kyverno, OPA Gatekeeper) can require SLSA provenance verification before allowing a pod to be scheduled:

# Kyverno policy: require SLSA provenance
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-slsa-provenance
spec:
  rules:
    - name: check-slsa
      match:
        resources:
          kinds: [Pod]
      verifyImages:
        - imageReferences: ["registry.company.com/*"]
          attestations:
            - predicateType: "https://slsa.dev/provenance/v0.2"
              attestors:
                - entries:
                    - keyless:
                        issuer: "https://token.actions.githubusercontent.com"
                        subject: "https://github.com/myorg/*"

The SLSA framework is evolving rapidly. As tooling matures, achieving Level 2 and 3 provenance for your own software is increasingly accessible with minimal configuration overhead—and the assurance it provides is a meaningful improvement in your supply chain security posture.

SLSA
supply-chain
build-provenance
sigstore
cosign
DevSecOps
SBOM

Check Your Security Score — Free

See exactly how your domain scores on DMARC, TLS, HTTP headers, and 25+ other automated security checks in under 60 seconds.