Supply-Chain Attacks
Every other page in this book quietly assumed one thing: that the inputs to your pipeline are trustworthy. Your dependencies are what they claim to be, your base image is clean, your CI runner does only what your config says. Platform engineering baked best practices into a golden path — but a golden path built on a poisoned dependency just paves the road to compromise faster. This page removes that assumption and looks at the system from the attacker’s side.
The shift that makes supply-chain attacks so dangerous is one of target. Breaking into a hardened, monitored production system is hard. But you didn’t write most of the code running there — the vast majority is third-party dependencies, base images, and build tooling. So the modern attacker reasons: why break into the running app when I can poison something it’s built from, and let your own trusted pipeline ship my code to production for me? The supply-chain security page armed you with defenses; this page shows the attacks those defenses exist to stop, as mechanisms — so you understand the shape, not just the headline.
Why the supply chain is the soft target
Section titled “Why the supply chain is the soft target”Think about the trust you extend without noticing. A single npm install or pip install can pull in
hundreds of transitive packages, each maintained by a stranger, any one of which runs with your
application’s privileges. Your Dockerfile’s FROM line inherits an entire operating system you didn’t
build. Your CI runner executes with credentials that can push to your
registry and deploy to production. Each is a trust relationship, and
each is a door.
OLD TARGET NEW TARGET (supply chain) ────────── ───────────────────────── attack the running app ──hard──► attack what BUILDS the app │ ┌─────────────────────────────────────────────────────────────┐ │ dependencies ──► base image ──► CI/build ──► artifact ──► PROD │ │ ▲ ▲ ▲ │ │ typosquat / poisoned compromised │ │ dep confusion base image build system │ └─────────────────────────────────────────────────────────────┘ your own trusted pipeline ships the attacker's code for youThe attacker’s leverage is that your pipeline is trusted. Everything downstream — the reviewers, the scanners, the deploy — assumes the inputs were clean. Poison an input early enough and the whole trusted machine becomes a delivery mechanism for the attacker.
The attack shapes
Section titled “The attack shapes”These are the recurring mechanisms. None requires touching your running infrastructure.
Typosquatting
Section titled “Typosquatting”The attacker publishes a malicious package with a name almost identical to a popular one — a transposed letter, a hyphen vs underscore, a plausible misspelling. A developer fat-fingers the name (or copies it from a stale tutorial), installs the impostor, and its install scripts run with full privileges. The malicious code often also re-exports the real package’s API so everything appears to work — the payload runs silently in the background.
Dependency confusion
Section titled “Dependency confusion”A subtler trick that exploits how package managers resolve names. Many organizations use internal
packages (e.g. acme-internal-auth) pulled from a private registry. If the build is configured so that a
public registry is also searched, an attacker can publish a package with the same internal name to the
public registry, often at a higher version number. The resolver, seeing a higher version available
publicly, pulls the attacker’s package instead of the legitimate internal one — no typo required, just a
naming and resolution gap the attacker walks through.
Compromised build system
Section titled “Compromised build system”Instead of poisoning a dependency, the attacker compromises the pipeline itself — a malicious or compromised CI plugin, a leaked runner credential, an action pulled from a mutable tag that gets swapped. This is the most dangerous shape, because the build system sits after your source review and before the artifact is signed and shipped. The attacker can inject code into the artifact at build time, so the source in git is clean, the diff reviewers approved is clean, and yet the built artifact contains the payload. Your audit trail shows nothing wrong.
Poisoned base image
Section titled “Poisoned base image”Your Dockerfile starts FROM some-base:latest. If that base image — or a layer
it depends on — is malicious or compromised, every container built on it inherits the payload. Using a
mutable tag like latest makes this worse: the image you pull today is not guaranteed to be the bytes you
pulled and vetted last week. You inherited an entire OS on trust, and the trust was misplaced.
Mapping the defenses
Section titled “Mapping the defenses”Here is the payoff of Part 8: each defense you learned maps directly onto a specific attack shape above. They are not abstract good hygiene — they are countermeasures with targets.
| Attack shape | Primary defense | Why it works |
|---|---|---|
| Typosquatting | Pinned, hash-verified dependencies + a lockfile | You install exactly the bytes you vetted; a wrong-named impostor doesn’t match the pinned hash |
| Dependency confusion | Explicit registry/scope config; never silently fall back to public | The resolver can’t be tricked into preferring a public impostor of an internal name |
| Compromised build system | Provenance / signed artifacts (SLSA-style) + least-privilege CI | A signature ties the artifact to the build that made it; deploy refuses anything unsigned or tampered |
| Poisoned base image | Image scanning + pinned image digests, minimal base | Pin @sha256:… not latest so you run vetted bytes; scanning catches known-bad contents |
| Any of the above | An SBOM (software bill of materials) | When a bad package is disclosed, you can answer “are we affected?” in minutes, not days |
Read the table as a single strategy with two themes.
Pin and verify, everywhere. Typosquatting and poisoned base images both exploit ambiguity — a name or
a latest tag that can resolve to bytes other than the ones you checked. Pinning to a cryptographic
hash (a lockfile entry, an image @sha256: digest) removes the ambiguity: you get the exact bytes you
vetted, or the install fails. The mutable name was the vulnerability; the immutable hash is the fix.
Provenance and least privilege for the build. Against a compromised build system you can’t trust the artifact’s contents alone, because the build is what was subverted. So you attach provenance — a signed, verifiable record of what built this artifact, from what source, how — and have your deploy step refuse anything whose provenance doesn’t check out. Combined with a least-privilege CI pipeline (short-lived, narrowly-scoped credentials, pinned actions), you shrink both the chance of compromise and the blast radius if it happens.
The thread
Section titled “The thread”The manual, error-prone step these defenses remove is trusting your build’s inputs by hope and hand-audit
— assuming a package name resolves to the code you think it does, that FROM …:latest is the image you
vetted, that a clean source review means a clean artifact, and, when bad news breaks, scrambling by hand to
work out whether you’re exposed. Pinning replaces “probably the right package” with “exactly these bytes or
fail.” Provenance replaces “the source looked fine” with “this artifact is cryptographically tied to a build
we trust.” An SBOM replaces a frantic manual audit with a query. Production gets safer because the trust you
were extending implicitly — to strangers’ packages, to base-image maintainers, to your own build runner —
becomes explicit and verified, and the attacker’s favorite move (let your trusted pipeline ship their
code) stops working.
The cost is discipline and friction: lockfiles to maintain, digests to update, signing infrastructure to
run, SBOMs to generate and store. It is genuinely more work than pip install and FROM ubuntu. But the
trade is the same one this entire book has been making — a small, deliberate, up-front cost to remove a
manual leap of faith that, left in place, is exactly where a catastrophe enters.
That closes Part 10. You now have the advanced lenses — the control loop behind everything, meshes and eBPF under the network, progressive delivery and chaos around change and failure, operators and platforms for leverage, and now the adversary’s view of the whole pipeline. It’s time to put it all together. The final Part is the capstone: a single project that wires the entire book into one working system — start at Part 11 · Capstone.
Check your understanding
Section titled “Check your understanding”- What assumption do supply-chain attacks exploit, and why is “what builds the app” an easier target than the running app itself?
- Distinguish typosquatting from dependency confusion. Why does dependency confusion not require the developer to make any mistake?
- Why is a compromised build system the most dangerous shape, and why does source review not catch it?
- Map each attack shape to its primary defense. Explain the unifying role of pinning to a cryptographic hash (a lockfile entry or image digest).
- Using the book’s thread, what manual step does an SBOM remove, and when does that removal pay off most?
Show answers
- They exploit the assumption that the inputs to your pipeline are trustworthy — dependencies, base images, and the build system. “What builds the app” is easier because most of that code is third-party and unreviewed, and poisoning an input lets your own trusted pipeline ship the attacker’s code to production for them, no break-in required.
- Typosquatting publishes a malicious package with a name nearly identical to a popular one and waits for a typo or stale copy-paste. Dependency confusion publishes a package with the same name as an internal one (often a higher version) to a public registry, so the resolver prefers the public impostor — no developer mistake needed, just a registry-resolution gap.
- The build sits after source review and before the artifact is signed, so a compromised build can inject code into the artifact while the git source and the reviewed diff stay clean. Source review can’t catch it because the malicious code never appears in the source — only in the built bytes.
- Typosquatting → pinned hash-verified deps; dependency confusion → explicit registry/scope config;
compromised build → signed provenance + least-privilege CI; poisoned base image → scanning + pinned
digest. Pinning to a cryptographic hash removes the ambiguity a name or
latesttag allows: you get the exact bytes you vetted or the install fails. - An SBOM removes the frantic, days-long manual audit of “are we affected?” after a bad package is disclosed — turning it into a query against your inventory. It pays off most under pressure, right after a disclosure, exactly when a manual audit is slowest and riskiest.