For two decades the threat model was what the application did wrong at runtime. Application security (OWASP) covers that. The supply chain — what was shipped into the application before the user ever ran it — was assumed out of scope because it was somebody else’s job. SolarWinds (2020), Log4Shell (2021), and the npm event-stream incident (2018) ended that assumption: attackers who cannot crack the application crack the build pipeline instead, because the build pipeline is trusted, and trusted code is undefended code.
This topic is the defence of the supply chain: the artefact manifests, the signing mechanisms, the maturity ladder, and the dependency hygiene that makes any of it hold.
The Supply Chain as an Attack Surface
The chain has many links; any one is a viable entry point:
| Link | What an attacker can do |
|---|---|
| Source | Push a malicious commit through a compromised maintainer account (the SolarWinds path) |
| Dependencies | Publish a typosquatted package (the event-stream path); compromise a transitive maintainer |
| Build pipeline | Tamper with the CI runner so the artefact contains more than the source (the SolarWinds path again) |
| Artefact registry | Replace a published image with a malicious copy |
| Deploy | Pull a different digest than the one certified, via mutable tags |
Each link is a place the artefact could be modified between what the developer shipped and what the operator ran. The whole defensive program of supply chain security is collapsing that gap to zero.
SBOMs (Software Bills of Materials)
An SBOM is a machine-readable manifest of every component that went into an artefact: direct and transitive dependencies, their versions, their licences, their hashes. Two formats dominate: SPDX and CycloneDX.
What an SBOM enables:
- Vulnerability matching: when a CVE drops, you grep your SBOMs and learn “where is this vulnerable library deployed, in which artefacts, in which environments”.
- Licence compliance: machine-checked, not “have we audited this repo yet?”.
- Provenance auditing: an SBOM signed alongside the artefact says “this artefact contains exactly these dependencies, by name and hash”.
An SBOM is necessary, not sufficient. Without a signed attestation that the SBOM corresponds to a real artefact built from a real source, it is just a file someone wrote.
Signed Artefacts: Sigstore and Cosign
Signing an artefact proves who built it and when. The signing key creates a chain: if you trust the key, you trust the artefact.
| Technique | Property | Failure mode |
|---|---|---|
| PGP / GPG signing | Long-lived private key signs artefact | Key leaks → every artefact ever signed by it is suspect |
| Cosign (keyless) | One-time key per artefact, tied to an OIDC identity via Fulcio | No long-term key to leak; logs (Rekor) attest the binding |
| Cosign (key-based) | Stable key, similar mechanics to GPG | Same key-rotation cost, but easier automation |
| In-toto attestations | Multi-stage pipeline provenance signed at each stage | Heavier setup; maps precisely to SLSA L3+ requirements |
The breakthrough of Sigstore is keyless signing: instead of a permanent private key, the build pipeline proves its identity via OIDC (GitHub Actions token, GitLab CI, …) and Fulcio issues a short-lived certificate valid only for this artefact. The certificate is recorded in the Rekor transparency log, which is append-only and publicly auditable.
The property bought: anyone can verify who built an artefact, when, against what source commit — without trusting a key the maintainer has to keep in a vault.
SLSA: The Maturity Ladder
SLSA (slsa.dev, “slopsa”) is the framework the industry uses to measure supply chain integrity, in four levels:
| Level | Requirement | Closes which attack |
|---|---|---|
| L1 | Build process documented; SBOM available | Hides nothing from audit |
| L2 | Build is hosted on a managed, tamper-resistant platform (read-only build inputs, isolated runner) | Build-server tampering |
| L3 | Build platform guarantees the provenance attestation is unforgeable — generated by the platform, not by the build script | Provenance forgery (the SolarWinds failure) |
| L4 | Reproducible builds + hermetic, independently-verifiable two-party approval | Even the maintainer acting alone cannot ship a malicious artefact |
Reaching SLSA L3 buys you the property that SolarWinds-style attacks fail. It is increasingly a procurement requirement (US executive order 14028 mandates SBOMs for software sold to the federal government; SLSA L2/L3 is the natural match).
Dependency Hygiene
Signing and attestations tell you your build is what it claims to be. They do not protect you from a malicious dependency you knowingly depended on. Three practices compound:
- Pin direct deps to a hash —
lodash@4.17.21is mutable;lodash@npm:4.17.21resolved to a specificsha512is immutable. Pin to the hash, the SHA, the digest — never the tag. - Lock transitive deps too —
package-lock.json/yarn.lock/Cargo.lock/go.sumrecord the resolved tree. Commit the lockfile. Verify reproducible installs. - Vet, don’t just install — there are ~3,000 new npm packages per day, many typosquatted. Vetting the reputation of a dependency (download counts, maintainer history, GitHub stars activity) before adoption is no longer optional.
Two complementary tools close the loop:
- Dependabot / Renovate pulls newer versions when patched; the merge is human-reviewed.
- OSV-Scanner / Trivy / Grype cross-references your SBOM against known vulnerability databases on every commit and every artefact build.
The full pattern: pin → lock → scan → update through review.
Trust Policies in CI
The deploy pipeline is the last gate before production. Three policies harden it against supply-chain compromise:
if: from_hash(artefact) AND provenance == signed_by_known_identity— do not deploy anything whose attestation fails. This is the runtime enforcement of SLSA L3.- Dependency pinning at the runner image itself — building on
ubuntu:latestmeans someone else chose your build environment; building onubuntu:22.04@sha256:...means your build is reproducible. - OIDC trust, no long-lived cloud credentials in CI — the runner proves its identity to the cloud and receives short-lived role assumption; a compromised runner cannot exfiltrate a deploy key.
Practice Trajectory
- Generate an SBOM (CycloneDX or SPDX) for a small application. Resolve one CVE listed against it by upgrading the offending dependency; re-generate; confirm the CVE is gone.
- Set up Cosign keyless signing in a GitHub Actions pipeline. Push an image, sign it, verify the signature against the Rekor transparency log. Note what proves what.
- Audit your own dependency file. Find one transitive dependency you cannot explain (
why isunderscorein my lockfile?). Trace its introducer. - Score a project at SLSA. Where is it L1, where is it L2, what would L3 take? Write the gap.
- Sketch the runbook for “a CVE just dropped in a library you use in production.” Which tool surfaces the affected artefacts; what branches the patch; what gates the deploy?
When It’s the Right Tool
| Situation | Takeaway |
|---|---|
| New artefact shipping | Generate an SBOM and sign it; require both at deploy time |
| Deploying third-party images | Verify the signature, the digest, the attestation — never the tag |
| A central platform team | Hold vendors to SLSA L2 minimum; L3 for anything that touches production data |
| A library release process | Pin the lockfile in version control; automate CVE scans and review-bounded upgrades |
| Trusting “it came from the official repo” | No — verify the signature, the digest, and the attestation; repositories can be compromised too |