Back to Blog

Secure crypto infrastructure: SLSA L3 Provenance for Docker Images - How We Made Our Builds Verifiable

T

Thanh Vo

Author

April 5, 2026
7 min read
Secure crypto infrastructure: SLSA L3 Provenance for Docker Images - How We Made Our Builds Verifiable

In March 2026, axios was compromised. A hijacked npm maintainer account published malicious versions to npm registry. The backdoor installed a credential-stealing RAT, exfiltrated cloud keys, and deleted itself after three hours.

This wasn't new. The Shai-Hulud worm had already hit hundreds of npm packages, and tainted Debian base images were still spreading the 2024 XZ Utils backdoor more than a year later.

The core problem was always the same: everyone downstream had to trust the artifact blindly. There was no cryptographic record of who built it, from what commit, or in what environment. A signature only proved the account. It said nothing about whether the account was compromised or if the code matched git.

At Fystack, we build custody infrastructure for crypto. Security and supply chain integrity are not optional for us - a tampered image in our environment doesn't mean a bug, it means compromised keys and drained wallets. To understand how we solved this, we first need to talk about a gap most teams never notice.

The Verification Gap Nobody Talks About

When you run docker pull someone/image:latest, you receive a SHA-256 digest. That digest is a content hash, proves the bytes you received match what was stored. It says absolutely nothing about how those bytes were produced.

Most people stop there. Some go one step further and check for a signature. A valid signature proves a specific identity approved the artifact. It still tells you nothing about whether the code that produced it was tampered with during the build.

How Checksum is using in Supply Chain

The gap lives between "signed" and "provable." A malicious actor who gains access to your CI runner can build whatever they want and sign it with your legitimate credentials. A supply chain attack that poisons a dependency used during your build will produce a validly-signed image containing malicious code. The signature remains intact throughout.

Supply Chain threads

Closing that gap requires a third guarantee, one that most open source projects don't yet have: provenance – a cryptographically signed record of the exact source commit, build environment, workflow, and parameters that produced the artifact, generated by a process isolated from the build itself.

That's the foundation of SLSA

What SLSA Actually Means (Beyond the Acronym)

Supply-chain Levels for Software Artifacts was developed by Google and is now governed by the OpenSSF. It defines a graduated framework of security guarantees for build pipelines, organized into levels.

SLSA Build Levels
  • L1: You get a provenance document that records what was built and how. It’s better than nothing and useful for auditing, but completely untrusted. An attacker can forge it easily.
  • L2: The provenance is now cryptographically signed by the CI platform. This prevents tampering after the build and raises the bar for casual attackers. However, the same job that builds the image is also responsible for generating and signing the provenance about itself. If the build is compromised, the provenance can still be faked.
  • L3: The provenance is generated in a completely isolated process, separate from the build job. It runs with its own identity and signing credentials, and the build job has no way to influence it. This is what makes the provenance non-forgeable.

In short, we can imagine:

  • No SLSA / L1:
    “Trust me, I built this.”
  • SLSA L2:
    “Our CI built this, but if the CI job is compromised, the proof can be faked.”
  • SLSA L3:
    “This image was built by our CI in a locked-down environment, and we can prove it, even if the build job itself is fully compromised.”

The bar has moved.

SLSA L2 is no longer enough for anything considered hardened. Serious infrastructure providers now treat SLSA L3 as the baseline.

Google ships its official container images at SLSA L3. GitHub builds Artifact Attestations on top of SLSA L3. Bitnami’s Secure Images are SLSA L3, with public verification keys published at a well-known URL.

This is the new standard.

The old SLSA v0.1 draft had an L4 requiring hermetic builds and mandatory two-party code review, but the SLSA working group dropped it, the requirements were too prescriptive and hard to verify consistently across different ecosystems and toolchains.

The Critical Difference: BuildKit vs. SLSA Generator

This is where most implementations go wrong, and where most blog posts gloss over the detail that actually matters.
docker/build-push-action ships with provenance: true. Enable it, and BuildKit attaches a provenance attestation to your image. It works. It's convenient. It is also self-attested, which means it provides Build L2 guarantees, not L3.

BuildKit Provenance (provenance: true)

  • Generated in the same job as the build.
  • Forgeable if the build is compromised.
  • SLSA L1–L2.

SLSA L3 Provenance (via slsa-github-generator)

  • Generated in a separate isolated job.
  • Receives only the image digest.
  • Not forgeable even if the build is compromised.
  • Signed by the SLSA generator's identity.

Key difference: BuildKit = convenient but trustable only if the build is clean.
SLSA L3 = tamper-proof provenance.

How Fystack apply SLSA

Every image we release runs through three sequential jobs. No single job can do everything.

SLSA Integrated pipeline

Job 1: Build & Push
Uses BuildKit to compile and push the image. We disable native provenance and only keep the immutable image digest as output.

Job 2: SLSA L3 Provenance
Runs in a completely isolated job using slsa-framework/slsa-github-generator. It receives only the final image digest, independently verifies the source repository, commit, and workflow via GitHub APIs, and generates a non-forgeable SLSA Level 3 attestation. Even if Job 1 is fully compromised, this provenance cannot be faked.

Job 3: Signing & Attestation

  • Signs the image using cosign with keyless signing (GitHub OIDC + Fulcio). No private keys ever touch the repository or runner.
  • Generates a full SPDX SBOM with Syft and attests it to the image.
  • Stores signatures and attestations using OCI 1.1 referrers mode to avoid tag pollution and work cleanly with immutable tags.

The final image carries five tightly bound artifacts on the same digest:

  • Image layers
  • BuildKit SBOM (for Docker Scout)
  • Cosign signature
  • SLSA L3 provenance
  • Sigstore-attested SPDX SBOM

All stored as OCI referrers.

We've open sourced the entire pipeline as a reusable GitHub Actions workflow at fystack/slsa-workflows - you can drop it into your own repository and get SLSA L3 provenance without building the pipeline from scratch.

What Verification Looks Like

Downstream consumers can verify the image independently with two simple commands:

# 1. Verify the cosign signature
cosign verify \
  --certificate-identity-regexp='https://github.com/fystack/slsa-workflows/.github/workflows/docker-build-slsa.yml@.*' \
  --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
  fystacklabs/apex:v1.0.54

# 2. Verify SLSA L3 provenance
slsa-verifier verify-image \
  --source-uri github.com/yourorg/your-repo \
  fystacklabs/apex@sha256:...

If the build was tampered with (for example, code injected outside the tagged commit), the provenance check fails hard even if the signature is still valid.

All signatures and attestations are also permanently recorded in Rekor, Sigstore’s public transparency log. This creates an immutable, independently auditable record that cannot be altered even if your registry is compromised.

For example, we include the Rekor Log of our provable image in our release: View on Rekor Search

RekorDB

What This Still Doesn't Solve

This pipeline is strong, but it is not magic. Supply chain attacks still happen every day.

Supply Chain Attack scenarios

Dependency attacks remain a real threat. A malicious package like event-stream can be legitimate at build time. Your SBOM, provenance, and signature all pass, yet the image contains malware. SBOM gives visibility, not prevention.

Base image risks are inherited. Backdoors like XZ Utils hid in official Debian images for over a year. Your provenance records the base you used, but cannot tell you it was compromised. Pinning by digest helps, but does not eliminate the risk.

Malicious maintainers bypass everything. If a trusted committer merges backdoored code, SLSA L3 still passes. It proves the pipeline ran correctly, not that the code was safe. Code review and branch protection remain essential.

Containers now have solid supply chain tooling. Most language registries such as npm and PyPI still lag far behind. That is the bigger gap.

The Standard Is Moving

Three years ago, SLSA L3 was considered advanced security theater, something only Google did internally.

Today, it’s becoming table stakes. What used to be aspirational is now baseline expectation for serious projects.

The question for open source maintainers has shifted from "Should we adopt SLSA L3?" to "Why haven’t we done it yet?"

The tools are free, mature, and maintained by Google and the OpenSSF. The effort is real but measured in hours, not weeks.

Your users run your code in production. They deserve more than “trust me.” They deserve cryptographic proof.

Building provable supply chains for your own project? Open an issue on fystack/slsa-workflows – we'd like to hear what you're working on.

Further Reading

Build Secure, Compliant Crypto Payment Infrastructure


Stablecoin payments demand more than wallets.
They require automation, policy enforcement, and security that scales with volume and regulation.

Share with us what you are building and we’ll show how Fystack’s MPC wallets, KYT integrations, and consolidation engine fit your architecture.


Not ready yet?
Join our Telegram to follow architecture updates and product discussions. https://t.me/+9AtC0z8sS79iZjFl

Share this post