Security

Software Supply Chain Security: SBOM, SLSA, and Provenance

How to secure your software supply chain with SBOMs, SLSA build integrity levels, sigstore/cosign artifact signing, and verifying provenance in CI/CD.

March 9, 20266 min readShipSafer Team

Software Supply Chain Security: SBOM, SLSA, and Provenance

The SolarWinds, Log4Shell, and XZ Utils incidents made software supply chain security a board-level concern. In each case, the attack vector was not the target's code — it was a trusted dependency, build tool, or update mechanism. Modern applications are 80-90% open-source software by volume. The security of that software — and the integrity of the build pipeline that assembles it — is now as important as the security of the code you write yourself.

This guide covers the three pillars of supply chain security: knowing what is in your software (SBOM), ensuring your build pipeline cannot be tampered with (SLSA), and verifying that artifacts are what they claim to be (provenance signing).

What Is a Software Supply Chain Attack?

A supply chain attack compromises software before it reaches the end user by targeting:

  • Open-source dependencies — Malicious packages published to npm, PyPI, or RubyGems (typosquatting, account takeover, malicious updates)
  • Build infrastructure — Compromising CI/CD systems to inject malicious code at build time (SolarWinds pattern)
  • Update mechanisms — Distributing malicious updates through legitimate channels
  • Transitive dependencies — The dependency of a dependency of a dependency contains malware

The attack surface is massive. The average Node.js application has 1,000+ transitive dependencies. A vulnerability or compromise in any one of them affects every application that depends on it.

SBOM: Software Bill of Materials

An SBOM is a machine-readable inventory of all components in a software artifact — packages, libraries, versions, licenses, and relationships. It is the software equivalent of a nutrition label.

Why SBOMs matter:

When a new vulnerability is announced (Log4Shell, Spring4Shell, OpenSSL), an SBOM lets you instantly determine which applications are affected. Without an SBOM, answering "do we use Log4j?" requires auditing dozens of repositories manually.

US Executive Order 14028 (2021) mandates SBOMs for software sold to the federal government. CISA has published guidance that SBOMs are a baseline for critical infrastructure software.

SBOM formats:

  • SPDX (Software Package Data Exchange) — Linux Foundation standard, ISO/IEC 5962
  • CycloneDX — OWASP standard, richer security metadata, supports VEX (Vulnerability Exploitability eXchange)
  • SWID — ISO/IEC 19770-2, used in enterprise software licensing

Generating SBOMs:

For containers:

# Syft (Anchore) — generates SPDX or CycloneDX SBOM from container images
syft myapp:latest -o cyclonedx-json > sbom.json

# Trivy — generates SBOM as part of vulnerability scan
trivy image --format cyclonedx myapp:latest > sbom.json

For Node.js projects:

# CycloneDX Node.js module
npx @cyclonedx/cyclonedx-npm --output-format JSON --output-file sbom.json

For Python:

# pip-audit with SBOM output
cyclonedx-py --output sbom.json

Integrating SBOM into CI/CD:

- name: Generate SBOM
  run: syft ${{ env.IMAGE_NAME }}:${{ github.sha }} -o cyclonedx-json > sbom.json

- name: Scan SBOM for vulnerabilities
  run: grype sbom:./sbom.json --fail-on high

- name: Attach SBOM to release
  uses: actions/upload-artifact@v4
  with:
    name: sbom-${{ github.sha }}
    path: sbom.json

VEX (Vulnerability Exploitability eXchange):

VEX is a companion to SBOM. Where SBOM says "this software contains component X," VEX says "component X has CVE-Y, but it is not exploitable in this product because the vulnerable function is never called." This dramatically reduces false positives from SBOM-based vulnerability scanning.

SLSA: Supply-chain Levels for Software Artifacts

SLSA (pronounced "salsa") is a framework of security requirements for the build pipeline itself. It ensures that the artifact you deploy was produced by the build process you think it was, with the code you think it contains.

SLSA defines four levels of increasing assurance:

LevelRequirementsProtection Against
SLSA 1Documented build process, provenance generatedAccident, ad-hoc builds
SLSA 2Hosted build service (GitHub Actions, Cloud Build), signed provenanceTampering post-build
SLSA 3Source + build both auditable, builds run in isolated, ephemeral environmentsCompromised build system
SLSA 4Two-party code review, hermetic reproducible buildsInsider threats, insider compromise

Most organizations should target SLSA Level 2 as a practical baseline — it requires a hosted build service and signed provenance, both of which are achievable with standard CI/CD tooling.

Generating SLSA provenance with GitHub Actions:

name: Build and Attest

on:
  push:
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      digest: ${{ steps.build.outputs.digest }}
    steps:
      - uses: actions/checkout@v4

      - name: Build container
        id: build
        run: |
          docker build -t myapp:${{ github.ref_name }} .
          DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' myapp:${{ github.ref_name }})
          echo "digest=${DIGEST}" >> $GITHUB_OUTPUT

  provenance:
    needs: [build]
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
    with:
      image: myregistry/myapp
      digest: ${{ needs.build.outputs.digest }}
    secrets:
      registry-username: ${{ secrets.REGISTRY_USERNAME }}
      registry-password: ${{ secrets.REGISTRY_PASSWORD }}

This uses the SLSA GitHub Generator project to produce SLSA Level 3 provenance automatically.

Sigstore: Keyless Signing with cosign

Sigstore is a set of open-source tools for signing and verifying software artifacts without managing long-lived private keys. It uses short-lived certificates tied to OIDC identity (GitHub Actions, Google, Microsoft) and records signatures in a public transparency log (Rekor).

cosign is the Sigstore tool for signing container images and other OCI artifacts.

Signing a container image (keyless, in CI):

- name: Install cosign
  uses: sigstore/cosign-installer@v3.5.0

- name: Sign the image
  run: |
    cosign sign --yes ${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
  env:
    COSIGN_EXPERIMENTAL: 1  # Keyless signing via GitHub OIDC

The signature is stored in the container registry alongside the image. The transparency log entry in Rekor provides a public audit trail — anyone can verify that the signature existed at a specific time.

Verifying an image before deployment:

cosign verify \
  --certificate-identity-regexp "https://github.com/my-org/my-repo" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  myregistry/myapp@sha256:abc123...

Using cosign in a Kubernetes admission controller:

Policy Controller (from Sigstore) enforces image signing at admission time:

apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-signed-images
spec:
  images:
    - glob: "myregistry/**"
  authorities:
    - keyless:
        url: https://fulcio.sigstore.dev
        identities:
          - issuer: https://token.actions.githubusercontent.com
            subjectRegExp: "https://github.com/my-org/.*"

Any pod attempting to use an unsigned image from myregistry will be rejected by the admission controller.

Dependency Management Best Practices

Supply chain security starts with your dependency choices:

  • Pin exact versions in lockfiles (package-lock.json, poetry.lock, go.sum) and commit them. Floating versions (^1.2.0) allow automatic upgrades to potentially malicious versions.

  • Use digest-pinned images in container builds: node:20-alpine@sha256:abc... instead of node:20-alpine. Tags are mutable; digests are not.

  • Enable Dependabot or Renovate for automated dependency updates. Security patches for dependencies are worthless if they are never applied.

  • Monitor for malicious packages with tools like Socket Security (real-time npm/PyPI analysis), Phylum, and Snyk Open Source.

  • Private package registries with an allow list of approved packages reduce the risk of typosquatting and namespace confusion attacks.

Supply chain security is not a single control — it is a collection of overlapping defenses. SBOMs give you visibility. SLSA gives you build integrity. Sigstore gives you verification. Together, they make it dramatically harder for an attacker to compromise your software without detection.

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.