Software Supply-Chain Security
- Software Supply-Chain Security
You don’t write most of your code
A modern application is mostly other people’s code. Run npm install on a small web app and you pull in hundreds of packages, written by people you have never met, who in turn depend on packages written by people they have never met. Your own source might be 5% of what ships; the other 95% is the software supply chain — dependencies, build tools, base images, CI/CD systems, and the channels that deliver updates to your users.
This makes supply-chain security a natural companion to memory corruption in Week 8: both are about trusting code you did not write and cannot fully see. With memory corruption the danger is a bug in trusted code; here the danger is that a component you imported is malicious, or was tampered with somewhere between its author and you. And because that component runs with your application’s full privileges, one poisoned dependency can be game over — no exploit required.
The supply chain is attractive to attackers for one reason: leverage. Compromise one popular library or one build server and you compromise everyone downstream at once — thousands of organizations from a single intrusion.
Where the attacks happen
The “chain” has many links, and an attacker only needs one:
author ─▶ source repo ─▶ build system ─▶ artifact registry ─▶ distribution ─▶ YOU
(account (CI/CD (npm, PyPI, (CDN, package
takeover, injection, Docker Hub, mirror,
malicious PR) SolarWinds) dependency update channel)
confusion)
Attacks on dependencies
- Dependency confusion (Alex Birsan, 2021) — if your build fetches an internal package name like
acme-utils, an attacker publishes a public package of the same name with a higher version number. The package manager, preferring the higher version, pulls the attacker’s code. Birsan used this to land code inside Apple, Microsoft, and dozens of others. - Typosquatting — a malicious
python-requstsorcolour(vsrequests,color) waiting for a typo or a careless copy-paste. - Malicious or hijacked packages — an attacker takes over a maintainer’s account (or buys a popular abandoned package) and ships malware in the next “patch” release. The trust you placed in last week’s version carries forward automatically.
Attacks on the build and distribution
- Build-system compromise — the SolarWinds attack (2020) inserted a backdoor into the build process, so the malicious code was baked into legitimately-signed releases shipped to ~18,000 organizations. The source code was clean; the build was poisoned.
- Distribution tampering — modifying an artifact after it is built but before you receive it (a compromised mirror or CDN).
Case study: the XZ Utils backdoor (CVE-2024-3094)
In March 2024 the security world narrowly avoided catastrophe. XZ Utils — a compression library bundled with virtually every Linux distribution — was found to contain a sophisticated backdoor targeting OpenSSH’s sshd, which would have granted remote code execution on hundreds of millions of systems. What makes it the defining supply-chain case study:
- It was a multi-year social-engineering campaign, not a hack. An attacker spent ~two years building trust as a helpful contributor, then exploited the burnout of the volunteer maintainer to be handed commit access. (Open-source maintainer fatigue is a security problem.)
- The malicious code was not in the git source — it was hidden in the release tarball and in obfuscated “test” files, activated only during the build. Anyone reading the repository would not have seen it.
- It was caught by luck: a Microsoft engineer (Andres Freund) noticed
sshdwas running ~500 ms slower than expected and investigated. Not by a scanner, not by review — by accident.
The lesson is sobering: signatures, code review, and version pinning would not have caught this, because the trusted maintainer signed it and the git source looked clean. It is the strongest argument for provenance, reproducible builds, and reducing dependency on under-resourced single maintainers.
Defending the supply chain
There is no single fix; the defenses stack into layers around two questions: what is in my software? and can I prove where it came from?
Know your ingredients: the SBOM
A Software Bill of Materials (SBOM) is a complete, machine-readable inventory of every component in a piece of software — like an ingredients label. When the next Log4Shell-style vulnerability drops, an SBOM answers “are we affected?” in seconds instead of weeks. Two standard formats dominate:
- SPDX (ISO/IEC 5962) — the Linux Foundation standard.
- CycloneDX — the OWASP standard, popular for security use cases.
Manage dependencies deliberately
- Pin and lock — use lock files (
package-lock.json,poetry.lock,Cargo.lock) so builds are reproducible and a dependency can’t silently change under you. - Scan continuously — Software Composition Analysis (SCA) tools (covered in application security) check your dependencies against vulnerability databases; Dependabot/Renovate automate the update PRs.
- Reduce and vet — fewer dependencies is less attack surface; prefer well-maintained projects over a one-person package with a clever name.
Prove provenance: signing and attestation
- Sigstore makes artifact signing practical. Its
cosigntool signs container images and blobs; keyless signing uses your identity (via OIDC) instead of long-lived keys, with Fulcio issuing short-lived certificates and Rekor recording every signature in a public transparency log — the same tamper-evident-log idea behind Certificate Transparency and the DNSSEC chain of trust. - Provenance / attestations — cryptographically signed statements (e.g. in-toto) describing how, where, and from what an artifact was built, so you can verify it came from your real pipeline and not an attacker’s laptop.
- SLSA (Supply-chain Levels for Software Artifacts, v1.0) — an OpenSSF framework defining graduated Build levels (L1–L3): from “provenance exists” up to “built on a hardened, isolated platform with tamper-proof provenance.” A maturity ladder for build integrity.
Governing frameworks
US Executive Order 14028 (2021) pushed SBOMs and supply-chain security into federal procurement, and NIST’s Secure Software Development Framework (SSDF, SP 800-218) codifies the practices. These are why SBOMs went from niche to contractual in a few years.
Worked example: inventory, scan, sign, verify
A typical modern pipeline generates an SBOM, scans it, then signs the artifact so downstream consumers can verify it. Using Anchore’s syft/grype and Sigstore’s cosign:
# 1. Generate an SBOM for a container image (SPDX format)
$ syft myapp:1.4.2 -o spdx-json > myapp.sbom.json
✔ Cataloged 214 packages
# 2. Scan that software for known vulnerabilities (SCA)
$ grype myapp:1.4.2
NAME INSTALLED FIXED-IN VULNERABILITY SEVERITY
libssl3 3.0.11 3.0.13 CVE-2024-XXXX High
log4j-core 2.14.1 2.17.1 CVE-2021-44228 Critical ← Log4Shell
# 3. Sign the image (keyless: authenticates via your OIDC identity,
# records the signature in the public Rekor transparency log)
$ cosign sign myapp:1.4.2
# 4. A downstream consumer verifies it really came from you
$ cosign verify --certificate-identity ci@example.com \
--certificate-oidc-issuer https://accounts.google.com myapp:1.4.2
Verified OK ← signature valid and logged in Rekor
The SBOM tells you what is inside, grype tells you what’s vulnerable, and cosign lets anyone downstream prove the artifact is genuinely yours and unmodified — exactly the gap that bit SolarWinds’ customers.
Key takeaways
- Most of your software is code you didn’t write; the supply chain (dependencies, build, distribution, updates) is a high-leverage target — one compromise hits everyone downstream.
- Attacks hit every link: dependency confusion, typosquatting, hijacked maintainers, build-system compromise (SolarWinds), and tampered distribution.
- XZ Utils (CVE-2024-3094) is the defining case: a patient social-engineering attack on a burned-out maintainer, hidden in the tarball not the git source, caught only by luck — defeating signatures and code review.
- Defenses stack: SBOMs (SPDX/CycloneDX) to know your ingredients; pinning + SCA scanning to manage dependencies; Sigstore signing, in-toto provenance, and SLSA to prove where artifacts came from.
- Verify it concretely:
syft(SBOM) →grype(scan) →cosign sign/verify(provenance via a transparency log).
References
- A. Birsan, Dependency Confusion: How I Hacked Into Apple, Microsoft and Dozens of Other Companies (2021). https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610
- Datadog Security Labs, The XZ Utils backdoor (CVE-2024-3094). https://securitylabs.datadoghq.com/articles/xz-backdoor-cve-2024-3094/
- OpenSSF — SLSA (Supply-chain Levels for Software Artifacts) v1.0. https://slsa.dev/
- Sigstore documentation (cosign, Fulcio, Rekor). https://docs.sigstore.dev/
- CycloneDX SBOM standard (OWASP). https://cyclonedx.org/
- SPDX SBOM standard (ISO/IEC 5962). https://spdx.dev/
- NIST SP 800-218 — Secure Software Development Framework (SSDF). https://csrc.nist.gov/pubs/sp/800/218/final
- CISA — Software Bill of Materials (SBOM). https://www.cisa.gov/sbom
syftandgrype(Anchore). https://github.com/anchore/syft
Related course pages: Application Security · Memory Corruption · Social Engineering · Cryptography · DevSecOps Fundamentals · Vulnerability Management
🛠️ Maintenance note: SLSA reached v1.0 in 2023 but its track/level structure is still evolving; SBOM mandates and EO/SSDF guidance change with each administration. Re-verify
syft/grype/cosigncommand syntax against the course VM each term — Sigstore’s keyless flags in particular have changed across releases.