SBOM Completeness with Direct & Transitive Dependencies
Table of Contents
While modern SBOMs are all about making dependencies and tooling “visible”, many
of them are still blind: they list only the libraries you specified in your
pom.xml and skip the dense forest of dependency trees that actually lands in
production. That blind spot is where malware, outdated libs, and licensing
issues like to hide. In this blog post, we will discuss why capturing both
direct and transitive dependencies matters, why Maven projects are
especially tricky, and how you can build a complete CycloneDX SBOM (with a
visual graph!) out of SafeDep Vet in one command. Along the way we compare
mainstream generators, map the regulatory pressure from laws like EU CRA, and
come up with a plan-of-action for devs/CISOs for closing the gaps.
If you are interested in learning more about EU CRA, please refer to our blog SBOM and the EU Cyber Resilience Act (CRA) – What Software Vendors Need to Know.
Background
Since its earliest manuals, Maven has promised “automatic updating” and
“dependency closures” (also known as transitive
dependencies), meaning that a entry in pom.xml silently expands into
every library required by that depencency and its descendants. The
official docs explains that there is “no limit to the number
of levels that dependencies can be gathered from,” with resolution performed
recursively at build time and the generated Project Dependencies pages regularly
show dozens of jars that never appear in the root POM. However, unlike build
systems and package managers like pnpm, cargo, pdm etc., Maven and the
Java ecosystem as a whole
lacks a solid foundation for lockfiles.
While this abstraction speeds development, it also conceals risk: unwanted or
outdated libraries can ride in unless a maintainer explicitly excludes them (eg,
optional dependencies).
Industry analysis of a million of Java packages found
that almost one-third of exploitable vulnerabilities live only in transitive
layers, invisible to tools that stop at first-level imports.
The Log4Shell crisis illustrated the danger when
organisations were compromised by an indirect copy of log4j-core they never
declared themselves, and attackers continue to probe that vector years later.
Problem: SBOMs That Stop at the First Branch
Maven hides the full dependency tree
Maven resolves transitive dependencies automatically; there is
“no limit to the number of levels that dependencies can be gathered from”. The
popular dependency:tree goal shows that expansion in
text, DOT or JSON formats, often revealing 10–50x more artefacts than appear in
the root POM. Research on 3 million Maven packages confirms that almost
one-third of projects are only vulnerable if those deeper layers are considered.
Risk concatanates in transitive layers
The Log4Shell exploit entered many Java applications that never declared Log4j directly; it arrived through indirect dependencies. Studies of real-world incidents show that updating a direct library often fails to patch flaws buried further down the graph, and tooling that stops at the first level cannot surface those blind spots.
Many SBOM generators still abbreviate
Issues filed against Syft report that versions prior to 1.30 listed only first-level packages for Java, omitting the dependency relationships required by auditors. However, NTIA’s minimum-elements document treats “X is included in Y” as the single mandatory relationship every SBOM must capture.
Regulatory momentum demands completeness
The EU Cyber Resilience Act will require vendors shipping to Europe to provide machine-readable SBOMs that cover complete dependency chains by December 2027, with fines up to €15 million for non-compliance. In the United States, Executive Order 14028 pushes federal agencies to buy only software that comes with an SBOM aligned to NIST guidance. Partial inventories will therefore fail procurement checks.
Operational impact for developers and CISOs
A flat SBOM hides which direct upgrade would excise a vulnerable transitive package, prolonging incident response times. In other words, a flat SBOM is ineffective in capturing the transitive dependencies. OpenSSF notes, it also obscures licence inheritance, exposing organisations to unexpected LGPL or GPL obligations.
Solution — Capture the Whole Graph
However, there are some ways to get around this situation, without having to switch to Gradle.
Extract the authoritative graph from Maven
Since maven already computes the full resolution, make use of it. The
mvn dependency:tree -DoutputType=dot command produces a
canonical graph that downstream tools can ingest. For automation, the
CycloneDX Maven plugin emits a CycloneDX v1.6 SBOM that
aggregates all direct and transitive dependencies in a single step.
Prefer graph-aware SCA tools
SafeDep Vet resolves the Maven tree, and writes a CycloneDX SBOM plus an optional DOT graph in one CLI invocation, eliminating manual glue code. By contrast, Syft requires environment flags for Java and still lacks complete graph output in certain modes, as its own issue tracker notes.
Embed verification in CI/CD
Add a pipeline step that:
- Generates
bom.json(CycloneDX) anddeps.dot(graph) at build time. - Validates the SBOM.
- Fails the build if any critical CVE is detected anywhere in the graph.
This satisfies CRA’s upcoming requirement for continuous vulnerability monitoring across the full supply chain.
And voila! Because the SBOM now contains edge data, remediation tools can pinpoint the closest direct dependency upgrade that eliminates a vulnerable indirect library, shortening mean-time-to-patch and reducing the risk of breaking upstream APIs.
Tools Landscape Overview
The landscape analysis spans Maven-native plugins that output CycloneDX files with full transitive coverage, open-source scanners such as Syft that are still refining their Java dependency-graph support, SPDX-focused licence tools, and SafeDep’s Vet, which combines graph-complete SBOMs with malware and policy checks. The table below compares their default abilities, export formats, and known quirks:
| Use case | Directs only | Transitives | Graph export | Notable quirks |
|---|---|---|---|---|
| Syft | ✅ | ⚠️ (Java needs SYFT_JAVA_RESOLVE_TRANSITIVE_DEPENDENCIES) | ❌ (flat list) | Includes test scope by default |
| CycloneDX Maven Plugin | ✅ | ✅ | via dependencyGraph | Runs in-build, no multi-ecosystem |
| SPDX-tools | ✅ | ❌ | N/A | Focus on license data |
| SafeDep Vet | ✅ | ✅ | --report-graph | Multi-lang with policy engine |
| OSV Scanner | ❌ | ✅ | ❌ | Transitive Maven scanning by default; —no-resolve disables transitives; no native graph export |
- dynamic-analysis
- oss
- malware
- security
Author
Arunanshu Biswas
safedep.io
Share
The Latest from SafeDep blogs
Follow for the latest updates and insights on open source security & engineering
nodemon-sudo: an npm Backdoor With No Install Script
nodemon-sudo copies the real nodemon byte for byte, adds nothing malicious to its own code, and injects one extra dependency, tslint-conf, a repackaged pino logger carrying a backdoor. There is no...
The Polymarket Trap: A Fake Arbitrage Bot, Ten npm Accounts, and Four Ways to Deliver an Infostealer
A GitHub repository posing as a Polymarket arbitrage bot accumulated 53 forks before anyone flagged the malicious npm package buried in its dependencies. Behind that repo: ten coordinated npm...
@marketfront: 25 npm Packages Reuse a Known Lure
On July 1, 2026, npm user marketfront batch-published 25 packages carrying the same README lure SafeDep has tracked across four earlier accounts (mr.4nd3r50n, pik-libs, t-in-one, emcd-vue): "Internal...
Miasma Worm Infects Multiple LeoPlatform npm Packages
A Miasma worm variant compromised a single maintainer account and used it to publish infected versions of 20 LeoPlatform npm packages within a 3-second window. The worm also pushed weaponized GitHub...
Ship Code.
Not Malware.
Start free with open source tools on your machine. Scale to a unified platform for your organization.