Your dependency graph is part of your attack surface
A software bill of materials tells you what you ship. Controlling supply-chain risk needs three further things: provenance for the build, a policy for adoption, and a rehearsed route to replace a component quickly.
An inventory is not a control
Software bills of materials have become a procurement expectation, and producing one is now straightforward: the build system emits it, the format is standardised, and the minimum elements are well defined. Many organisations have concluded from this that supply-chain security is largely handled.
An inventory tells you what you ship. That is genuinely useful—when an advisory lands, knowing within minutes whether you are affected is worth the investment. But it changes nothing about your exposure. A complete, accurate, continuously generated bill of materials for a system with a compromised build server, an unreviewed adoption process and no way to replace a transitive dependency describes the problem in high resolution.
Three further capabilities do reduce exposure: provenance for how the artefact was produced, a policy for what enters the graph, and a rehearsed path for getting something out of it.
Provenance answers the question an SBOM cannot
An SBOM asserts contents. Provenance asserts origin: this artefact was produced by this build system, from this source revision, with these inputs, and here is a signed statement to that effect that you can verify without trusting the party who handed you the artefact.
The distinction matters because most consequential supply-chain incidents have not involved a known-vulnerable library. They have involved a legitimate-looking artefact that did not correspond to the reviewed source—a build server that injected code, a release pipeline with a writable step, a package registry account that pushed a version nobody tagged.
The SLSA framework describes this as escalating levels of build integrity, and the early ones are achievable without restructuring how a team writes software: build on a hosted service rather than a developer machine, generate provenance automatically, and verify it before deployment. The verification step is the one teams skip, and without it the attestation is a file rather than a control.
Two practical implications follow. First, the deploy path must reject an artefact whose provenance does not validate, which means provenance verification is a blocking gate. Second, the source revision in the attestation must be the revision that was reviewed—which is only meaningful if the branch it came from enforces review, and if the build cannot be triggered from an arbitrary revision.
Decide adoption before the deadline
Most dependencies enter a codebase during a sprint, chosen by whoever needed them, on the evidence of a search result. The decision is rarely revisited and is almost never recorded.
A lightweight adoption policy changes the default without slowing delivery much. Useful criteria, applied proportionally to where the dependency sits:
| Question | Why it matters |
|---|---|
| How many maintainers have commit access, and is release automated from source? | A single-maintainer package with manual publishing is a single point of compromise |
| Does it run at build time, at request time, or in a privileged context? | A build-time dependency executes on your build system with its credentials |
| How large is its own transitive graph? | Adopting one package often means adopting forty |
| Is there a vulnerability disclosure process and a recent security fix? | Absence of both usually means absence of attention rather than absence of defects |
| What is the replacement cost if it becomes unmaintained? | This is the number that determines whether you can act later |
The last question is the one worth insisting on, because it is the only one about your own resilience rather than the upstream’s behaviour. A dependency with a high replacement cost in a privileged position is a commitment, and commitments should be made deliberately.
NIST SP 800-161 frames the same territory at an organisational level, connecting acquisition decisions to the technical controls that have to exist afterwards. The connection is the part that usually breaks: procurement asks questions at purchase, engineering adopts components continuously, and the two processes do not meet.
Build systems are higher-value targets than libraries
An attacker who compromises a popular library reaches everyone who uses it, after a delay, subject to review. An attacker who compromises your build system reaches your customers directly, signed by your key, with your provenance attached.
This reordering of priorities is uncomfortable because build infrastructure is usually the least-governed part of an engineering estate. Typical conditions include long-lived credentials with broad permissions, pipeline definitions editable by anyone who can push, caches shared across projects, and self-hosted runners that persist state between jobs.
The countermeasures are ordinary infrastructure hygiene applied somewhere it often is not:
- ephemeral runners, so nothing persists between builds;
- pipeline definitions protected by the same review requirement as source code;
- short-lived, workload-scoped credentials in place of stored secrets;
- signing keys held in a hardware-backed service that logs every use, not in a pipeline variable;
- separation between the build that produces an artefact and the process that publishes it.
None of this is novel. It is worth stating because a team that has invested heavily in dependency scanning and left its build system open has secured the lower-value target.
Rehearse the replacement, not the patch
When a serious advisory lands, the question is not whether you can identify affected systems—the inventory answers that. It is how long it takes to ship a version without the affected component, or with it replaced.
Most organisations discover their answer during the incident. Rehearsing it instead is cheap: pick a mid-tier dependency, remove it, and time the work end to end, including the tests that break for unrelated reasons and the service that turns out to embed an older copy.
Track two numbers from the exercise. The first is time to patched release for a component with an available fix. The second, and the more revealing, is time to replacement for a component with no fix—an unmaintained package, an abandoned upstream, a library whose maintainer declines to treat the issue as a vulnerability. A programme that can do the first in hours and has no answer for the second is prepared for the easier case.
Prioritisation during the real event should follow exploitation rather than severity. CISA’s Known Exploited Vulnerabilities catalogue is the most useful single input, because it distinguishes what is being used from what could be.
What a customer or regulator will ask for
The external demands are converging on the same set. Enterprise procurement asks for a bill of materials, a disclosure policy and a patch commitment. The EU Cyber Resilience Act requires manufacturers of products with digital elements to identify and document components, address vulnerabilities without delay and provide security updates for a defined support period.
Read as engineering requirements rather than paperwork, these reduce to capabilities: you can say what is in a release, you can receive and act on a report, and you can ship an update to a deployed version for as long as you promised. The third is the one that catches organisations out, because supporting an older release branch requires build reproducibility and test coverage that a fast-moving main branch does not automatically provide.
The useful sequencing is to build the capability and let the document fall out of it. An SBOM generated by a build you can reproduce, for an artefact whose provenance verifies, from a dependency set someone chose deliberately, is a credible answer. The same document produced by a script at audit time is a description.