When a security team asks "what's in our software," most point to an SBOM generated at build time from a package manifest. But that document only captures what a build tool declared — not what actually got pulled into the artifact that shipped. Between 2018 and 2024, some of the industry's most damaging supply chain incidents — event-stream, ua-parser-js, the xz utils backdoor, polyfill.io — didn't come from a package security teams knew about and chose to accept. They came from dependencies nobody had inventoried: transitive packages pulled in three or four levels deep, dev-only tools that leaked into production builds, and forked or renamed packages that evaded manifest-based scanning entirely. Sonatype and similar platforms built their reputation scanning declared dependencies against vulnerability databases. That leaves a gap for the packages that were never declared in the first place. This is the shadow dependency problem, and shadow dependencies risk management has to start before the SBOM does, not after.
What Counts as a Shadow Dependency?
A shadow dependency is any package that ends up in your build, runtime, or container image without being explicitly declared, reviewed, or tracked by your dependency management process. That definition covers more ground than most teams assume. Transitive dependencies are the biggest category: Sonatype's own 2023 State of the Software Supply Chain report noted that the majority of known vulnerabilities in open source components are found in transitive dependencies rather than the direct ones a developer typed into package.json or pom.xml. A single direct dependency can pull in dozens of transitive packages — Synopsys's Open Source Security and Risk Analysis report has repeatedly found that the average commercial codebase contains 500+ open source components, the overwhelming majority never directly chosen by anyone on the team.
Beyond transitive packages, shadow dependencies also include build-tool plugins fetched at CI time, dev dependencies that get bundled into production artifacts by misconfigured build steps, packages installed by lockfile drift between environments, and internal or vendored code copied into a repo without ever being registered as a dependency. None of these show up in a manifest-based inventory, which means none of them show up in the resulting SBOM either — even though every one of them executes with the same privileges as code the team actually chose.
Why Do Traditional SCA Tools Miss Them?
Traditional software composition analysis tools miss shadow dependencies because they were architected to read manifests, not to observe what a build actually resolves and installs. Tools like Sonatype Nexus IQ and Lifecycle scan package-lock.json, pom.xml, requirements.txt, and similar files, then match declared versions against known-vulnerability feeds. That workflow is effective for the specific problem it was built to solve — flagging CVEs in declared components — but it depends on the manifest being complete and current at scan time.
That assumption breaks constantly in practice. A npm install can resolve different transitive versions on different days depending on semver ranges and registry state, so a lockfile scanned on Monday can diverge from what a CI runner actually pulls on Friday. Manifest-based scans also generally can't see packages introduced by build plugins, container base image layers, or scripts that fetch code outside the standard package manager flow — all of which have been the initial vector in real incidents. This is exactly why manifest-completeness has become the limiting factor for any shadow dependencies risk management program built on top of a traditional SCA tool: the tool is only as good as the list it's given, and shadow dependencies are, by definition, not on that list.
What Have Real Incidents Cost Organizations?
Real incidents caused by unmanaged dependencies have already produced measurable, large-scale damage, not hypothetical risk. In November 2018, an attacker gained publish access to the event-stream npm package and injected a malicious sub-dependency called flatmap-stream, targeting the Copay Bitcoin wallet's users specifically — a payload that sat undetected in a widely used transitive package for roughly two months before discovery. In October 2021, the ua-parser-js package, downloaded roughly 7-8 million times a week at the time, was compromised and used to push cryptominers and credential-stealing malware to any project that pulled it in as a transitive dependency, often without direct awareness that the package existed in their tree at all.
The xz utils backdoor, discovered by Andres Freund on March 29, 2024, is perhaps the starkest example: a maintainer account that had built trust over roughly two years inserted an SSH-authentication backdoor into a compression library so deeply embedded in the Linux ecosystem that most organizations running affected distributions had no idea they depended on it, directly or transitively. And in June 2024, the compromise of the polyfill.io CDN service injected malicious JavaScript into more than 100,000 websites that had linked the script — often through a dependency chain several layers removed from the team that originally added it. In every one of these cases, the vulnerable component wasn't sitting on a risk-acceptance list waiting for a patch. It was invisible until the breach made it visible.
Does Generating an SBOM Solve This Problem?
Generating an SBOM does not solve the shadow dependency problem on its own, because an SBOM is only as accurate as the process used to produce it. Executive Order 14028 and the resulting NTIA and CISA guidance pushed SBOM adoption hard starting in 2021, and by 2024 SBOM delivery was a contractual requirement for many federal software vendors. That's real progress — but a manifest-derived SBOM, the kind most tooling produces by default, inherits every blind spot described above. If a package entered the build through a route the SBOM generator doesn't observe, it doesn't appear in the SBOM, and a document that omits real components creates false confidence that can be worse than having no SBOM at all.
An SBOM built for shadow dependencies risk management needs to be generated from what actually executes — build-time and runtime observation, container layer analysis, and dependency resolution snapshots taken at the moment of build — rather than solely from what a manifest file claims. That distinction is the difference between an SBOM that documents intent and one that documents reality.
Where Does Sonatype's Model Fall Short on Shadow Risk?
Sonatype's model falls short on shadow risk because it is fundamentally a policy-and-scanning layer over declared dependencies, not a discovery layer for undeclared ones. Nexus IQ and Lifecycle excel at what they were designed for: enforcing open source governance policy, blocking known-bad versions at the firewall, and giving security teams a component database to check declared packages against. That's valuable, and plenty of organizations rely on it as one layer of a supply chain program.
The gap is that this model assumes the inventory feeding it is complete. It doesn't reconstruct the full dependency graph as it actually resolves at build time across every language and package manager in a polyglot estate, it doesn't flag drift between a scanned lockfile and what a CI job later installs, and it treats build tooling, container base layers, and CI-fetched scripts as largely out of scope. For a team relying on Sonatype as their sole source of dependency truth, that means the exact category of risk described above — the transitive, the drifted, the build-time-only, the unregistered — can sit outside the policy engine's field of view indefinitely, unflagged because it was never in the dataset the engine was scanning against.
How Safeguard Helps
Safeguard is built to close that specific gap: it treats shadow dependencies risk management as a discovery problem first and a policy problem second. Instead of relying solely on declared manifests, Safeguard observes builds and runtime environments directly to reconstruct the dependency graph as it actually exists — including transitive packages several layers deep, build-tool plugins, container base image contents, and packages introduced by CI scripts outside the standard package manager flow.
That observed graph feeds SBOM generation that reflects what shipped, not what was declared, and Safeguard continuously diffs new builds against prior ones to surface drift the moment an unreviewed or unauthorized package enters an artifact — rather than waiting for the next scheduled scan to catch up with a manifest that has already changed. Every newly observed component is matched against vulnerability and malicious-package intelligence in near real time, so a compromised transitive dependency gets flagged based on what's actually running, not on whether someone remembered to declare it.
For teams that already use Sonatype for open source governance and license policy, Safeguard is designed to complement that investment rather than replace it: Sonatype's policy engine still enforces the rules once dependencies are known, while Safeguard makes sure the inventory feeding those rules — and the SBOM handed to auditors, customers, and regulators — actually reflects the software that shipped. That combination is what turns shadow dependencies risk management from a quarterly scanning exercise into a continuous, build-by-build guarantee.