The Five Stages: Source, Dependencies, Build, Artifact, Deploy
A team with mandatory two-person code review, signed commits, and a hardened repository was compromised through its build system. Every control they had operated on the source, and the attacker never touched the source. Controls do not average out across stages. A gap at one stage is a gap, regardless of how strong the others are.
The Concept Explained
The path from an idea to a running process passes through five distinct stages, each with its own trust assumption and its own attacker payoff.
SOURCE ──> DEPENDENCIES ──> BUILD ──> ARTIFACT ──> DEPLOY
│ │ │ │ │
what you what you what what is what runs
wrote imported assembles distributed
The property that makes this framing useful: each stage trusts the output of the previous one and cannot verify it. The build system does not know whether the source was tampered with. The registry does not know whether the build was clean. The cluster does not know whether the image in the registry is the one the build produced. Every stage boundary is a trust handoff, and an attacker only needs one of them to be unverified.
How It Works
Stage by stage
| Stage | Trust assumption | What an attacker gains | Example |
|---|---|---|---|
| Source | The code in the repo is what authors intended | Code review is bypassed or subverted; the change looks legitimate | Repo compromise, malicious contributor, stolen credentials |
| Dependencies | Imported packages do what they claim | Code execution inside your build and your runtime, without touching your repo | event-stream, dependency confusion, typosquatting |
| Build | The build faithfully transforms source into artifact | Output differs from input, and every downstream signature certifies the result | SolarWinds |
| Artifact | What was published is what was built | Substitution or modification between build and consumption | Codecov, registry compromise, tag mutation |
| Deploy | What runs is what was approved | Bypassing the entire chain by deploying something else | Direct cluster access, unverified images |
Each row is a different problem needing different controls, and they do not substitute for one another.
Why controls do not compensate across stages
The point that the opening scenario makes concrete.
SolarWinds had a compromised build stage. The source repository was not modified. So every source-stage control (review, signed commits, branch protection, static analysis on the repo) was operating correctly and inspecting something that was never attacked. The malicious code was inserted after those controls ran and before the signature was applied, which meant the resulting artifact was legitimately signed by the vendor's own key.
That produces a useful test for any control you are considering:
Which stage does this protect, and what does it assume about the stages before it?
Dependency scanning assumes the build is honest. Image signing assumes the thing being signed is correct. Admission policy assumes the registry content matches what was verified. Every control has an implicit dependency on the integrity of everything upstream of it, and stating that dependency is how you find the gaps.
The handoffs are the interesting part
Attacks cluster at the boundaries, because that is where verification is absent:
Source to build. Does the build system verify what it checked out? Building from a mutable branch means the build system trusts whatever the reference pointed to at that moment. Pinning to a commit digest makes the handoff verifiable.
Dependencies into build. Does the build verify what it downloads? Version ranges resolved at build time mean the artifact depends on what a registry served that day. Lockfiles and digests make it checkable (Lesson 2.3).
Build to artifact. Does anything record how the artifact was produced? Without provenance, the artifact is a blob whose origin is asserted by whoever pushed it. This is the handoff SLSA addresses (Module 4).
Artifact to deploy. Does the deployment verify what it is running? A mutable tag means the cluster resolves the name at pull time and may get something different from what was tested (Lesson 7.3).
The recurring pattern: wherever a name is resolved rather than a digest verified, there is a handoff an attacker can occupy.
Where effort actually goes, and where it should
The distribution of attention in most organisations does not match the distribution of leverage:
Effort spent Attacker leverage
Dependencies ████████████ Dependencies ██████
Artifact scan ████████ Build ██████████
Source review ██████ Deploy ████
Deploy ███ Source ███
Build █ Artifact ███
Dependency scanning dominates because it is easy to buy and produces visible output. The build system receives the least attention and offers an attacker the most: it holds credentials, has network access, and can modify what ships while remaining invisible to source-stage controls.
That mismatch is worth raising directly when arguing for investment. Module 3 is about closing it.
The stages are recursive
An uncomfortable observation that changes how you scope this work: your build system has its own supply chain.
The compiler, the base image the runner uses, the pipeline actions you invoke, the scanner you rely on, and the signing tool itself are all artifacts produced by someone else's five stages. Your dependency scanner is a dependency.
You cannot follow that recursion to the bottom, and nobody does. What you can do is decide where you stop and be explicit about it, which is the trust anchor question in Lesson 1.4. The practical version is that a small number of components, your build platform, your base images, and your verification tooling, deserve far more scrutiny than the average dependency, because a compromise there invalidates everything downstream including your ability to detect it.
When assessing an organisation's posture, walk the five stages and ask one question at each boundary: "what verifies the handoff?" In most cases the honest answer at three or four of them is "nothing, we trust the previous step." That list is your roadmap, and it is more useful than any maturity model, because it is specific to how your pipeline actually works.
In Production
- Map your own five stages before buying anything. The pipeline you have is rarely the pipeline on the architecture diagram.
- Write down each control's assumption. "This scanner assumes the build is honest" is the kind of statement that makes gaps visible.
- Prioritise the build stage. It is the least instrumented and the highest leverage.
- Look for name resolution. Floating tags, version ranges, and branch references are each a handoff where you accept whatever you are given.
- Treat build platform components as tier-one dependencies. A compromised scanner or signer defeats the controls that would otherwise catch it.
- Expect to be unable to finish. The recursion is infinite; the deliverable is a documented, deliberate stopping point rather than completeness.
Tradeoffs and Decision Framework
Depth at one stage against coverage across all five. A very strong control at one stage leaves the others as the path of least resistance. Basic coverage everywhere usually beats excellence in one place, because the attacker chooses the weakest handoff.
Verification cost against pipeline speed. Every verification adds latency and a failure mode to the build path. Verifying at the boundaries that matter beats verifying everywhere.
Pinning against currency. Digest pinning makes handoffs verifiable and means you no longer receive updates automatically, including security fixes. That tension is real, and Lesson 2.3 works through it.
Stopping point for the recursion. Scrutinising the build platform deeply is expensive and is the highest-value place to spend. Stopping too early leaves your controls resting on unverified tooling.
Common Mistakes
Assuming strong source controls protect the artifact. SolarWinds' source was never touched.
Buying a tool before mapping the stages. You end up with excellent coverage of a stage that was not your weakest.
Ignoring the handoffs. The controls exist inside stages; the attacks happen between them.
Treating floating tags and version ranges as convenience. They are unverified handoffs with an operational benefit attached.
Exempting build tooling from scrutiny. It is the one category whose compromise disables detection.
Believing any of this is finishable. The goal is a deliberate, documented trust boundary, not completeness.
Assessing maturity by tools owned. The useful measure is how many handoffs are verified, which is usually a smaller number than the tool inventory suggests.