17 September 2026
·5 min read
Platform & SREsoftware composition analysissupply chain securitySoftware Composition Analysis Has a Blind Spot: The Gap Between What You Declare and What You Run
Manifest-based dependency scanning tells you what you declared, not what actually executes in production. New research on lifecycle-aware software composition analysis shows why the gap matters — and what engineering leaders can do about it.
Most software composition analysis (SCA) tooling answers one question: what does your manifest declare? A package.json, a pom.xml, a go.mod — scanned, matched against a vulnerability database, and turned into a report. That report is useful, but it describes an intention, not a reality. Between the dependency you declared and the code that actually executes in production, components are resolved, transitively pulled in, repackaged, stripped, vendored into containers, and sometimes swapped entirely at build time.
A new study, From Component Snapshots to Lifecycle Traces: Agent-Based Software Composition Analysis, names this problem directly. The authors observe that existing SCA approaches — whether they inspect manifests, build environments, release artefacts, containers, or runtime state — produce only *stage-specific* views. Each is a snapshot. And a snapshot cannot tell you both where a component originated and where it ended up, because dependencies are transformed as they move through the lifecycle. The provenance question and the execution question are answered by different tools looking at different stages, and nobody joins them up.
For a CTO, this is not an academic nuance. It is the reason a clean SCA dashboard and a compromised production runtime can coexist quite comfortably.
Why the snapshot model breaks down
The uncomfortable truth is that the artefact you ship rarely matches the manifest you scanned. Three transformations are responsible.
- Transitive resolution. Your direct dependencies pull in indirect ones, and the resolved versions depend on the resolver, the lockfile state, and the timing of the build. The graph you scanned at commit time may not be the graph your build produced.
- Repackaging and vendoring. Build steps flatten, minify, tree-shake, and inline third-party code into bundles. A component that existed as a named dependency at development time becomes anonymous bytes inside an artefact — invisible to a manifest scanner, present at runtime.
- Container-layer drift. Base images bring their own system libraries, and multi-stage builds copy binaries across boundaries. What runs in the container is a union of your declared dependencies and everything the image inherited.
The result is two separate maps that never get overlaid: one showing *where components came from* (development-time provenance) and one showing *what is actually loaded and executed* (runtime reality). The SolarWinds compromise remains the canonical illustration — malicious code was injected into the build pipeline, so the source repository looked clean while the shipped artefact was not. Manifest scanning was structurally incapable of seeing it, because the manifest was never the problem.
What lifecycle tracing actually buys you
The research argues for treating software composition as a *trace* across lifecycle stages in place of a set of disconnected snapshots. The practical payoff is threefold.
- You can distinguish declared-but-unused from used-but-undeclared. A vulnerability in a package that is present in your lockfile but never loaded at runtime is a very different risk from a vulnerability in code that executes on every request. Snapshot SCA treats both as line items on the same list. Lifecycle context lets you triage by actual exposure.
- You can detect drift between build input and build output. If a component appears in the runtime that did not appear in the resolved dependency graph, that is a signal worth investigating — the exact class of anomaly that build-injection attacks depend on going unnoticed.
- You can attribute a runtime component back to its origin. When a CVE lands, the question is not "is this library in a manifest somewhere" — it is "is this library actually executing, in which service, introduced at which stage." That is a provenance-plus-runtime question, and it is the one incident responders are forced to answer manually under time pressure today.
Three actions for this week
You do not need to adopt a research prototype to close the most dangerous parts of this gap. You need to stop trusting the manifest as ground truth.
- Generate your SBOM from the built artefact, not the source manifest. Run SBOM generation as a post-build step against the actual container image or release bundle, using a tool that inspects binaries and layers in place of declaration files. Then diff it against the manifest-derived SBOM. Any component that appears in one but not the other is a question you want answered before an auditor or an attacker asks it.
- Add a runtime-reachability filter to your vulnerability triage. Before your team burns a sprint patching CVEs, separate the ones in code paths that actually load at runtime from the ones sitting inert in your lockfile. Even a coarse reachability signal changes the economics of remediation and stops your best engineers chasing findings that carry no production exposure.
- Pin the build and record provenance. Lock resolved dependency graphs, pin base image digests in place of tags, and capture build provenance attestations (SLSA-style) so that the map from build input to build output is reproducible and inspectable. Drift you can see is drift you can defend against.
The deeper point is that supply-chain security has been mislabelled as a scanning problem when it is a lifecycle-visibility problem. Adding a fourth scanner to the three you already run does not join the snapshots together. Understanding how a component moves from declaration to execution does.
Where this sits in delivery, not alongside it
This is not a problem you solve by buying another tool and bolting it to the side of a pipeline nobody owns end to end. It is solved inside delivery — where the same team that writes the build steps also owns the provenance attestations, the artefact-derived SBOM, and the reachability triage, and can reason about all three together. A qualified engineering pod approaches this the way it approaches any reliability question: by treating the pipeline as a system with observable inputs and outputs, instrumenting the build so the component trace is captured in place of reconstructed after an incident, and wiring the runtime signal back into triage so vulnerability work is prioritised by exposure in place of by dashboard volume. The mechanism is what makes it durable — the visibility survives the next base-image bump because it is built into how the artefact is produced.
Anystack embeds a senior pod into a client's codebase to make exactly these kinds of cross-stage properties explicit: build provenance, artefact-derived composition, and runtime reachability treated as one continuous trace in place of four disconnected reports. That work lands where it belongs — inside platform reliability and delivery, not as a separate security theatre running in parallel to the engineering that actually ships.
