arXiv:2609.19920v1 [cs.CR] 17 Sep 2026
Mind the Gap: How SBOM Specification Ambiguities Lead to Divergent Software Bills of Materials. An Empirical Tool Study. Alan Prado
Olivier Zendra
Univ. Rennes, Inria, CNRS, IRISA Rennes, France [email protected]
Univ. Rennes, Inria, CNRS, IRISA Rennes, France [email protected]
Philippe Boinot
Olivier Barais
ANSSI Rennes, France
Univ. Rennes, Inria, CNRS, IRISA Rennes, France [email protected]
Abstract
SBOMs thus improve supply chain transparency and help assess the risks associated with third-party dependencies [15]. This growing importance has prompted regulatory action. In the United States, the National Telecommunications and Information Administration (NTIA) established minimum requirements for SBOM content in 2021 [14]. In Europe, the Cyber Resilience Act (CRA) [8] goes further, mandating SBOMs for all software products placed on the EU market, with full compliance and enforcement due by December 2027. Implicitly, both frameworks assume that SBOM generation tools accurately reflect the actual dependencies of a software product. However, this assumption does not always hold.
Software Bill of Materials (SBOMs) will become mandatory starting in December 2027 under the European Cyber Resilience Act (CRA) [8]. Although previous studies have highlighted significant differences among SBOM generators, the reasons for these discrepancies remain unknown, as does whether they stem from implementation errors or deliberate design choices. In this paper, we evaluate three widely used SBOM generators across more than 3,000 JavaScript and Rust projects, using a groundtruth baseline derived from dependency lockfiles. Our results show that these tools diverge in terms of both dependency coverage and SBOM completeness. Importantly, most of these discrepancies are systematic rather than accidental: they arise from differing assumptions regarding dependency scope, naming, provenance, and representation, while others reflect inconsistent support for fields defined in SBOM specifications. These findings demonstrate that many of the observed discrepancies cannot simply be "fixed": they require clearer standardization. As SBOM generation becomes a legal compliance requirement, the choice of tool itself can influence the resulting SBOM, potentially becoming a source of undetected non-compliance. We argue that future SBOM standards should define canonical rules regarding dependency scope, provenance, and representation to improve interoperability and compliance.
In fact, several studies have evaluated SBOM generation tools and found that they often produce incomplete and inconsistent SBOMs, with different tools producing different results for the same project [20, 21, 24–26]. Tools disagree on which dependencies to include, how to name them, and which versions to report. This has been observed across multiple languages and package managers. This can clearly undermine key use cases such as vulnerability detection [3]. These studies document the divergences and, in some cases, hint at possible causes, but none systematically explains their nature or origin at scale. How much of the divergence stems from normalization artifacts, deliberate design choices, or tool errors, and in what proportion, remains unclear. This is the gap our work aims to address.
CCS Concepts • Software and its engineering → Software creation and management; Empirical software validation; • Security and privacy → Software and application security.
In this paper, we study two ecosystems with different characteristics. JavaScript has the largest package ecosystem in the world, built around a micro-package philosophy and spread across several package managers: npm, Yarn, and pnpm. Rust is a more recent language focused on memory safety and performance, with a single package manager, cargo. Both ecosystems use lockfiles, files that pin every dependency (direct and transitive) to an exact resolved version, ensuring reproducible installs, which makes it possible to compare tool-generated SBOMs against a reliable reference. We formulate three research questions:
Keywords Software Bill of Materials, Software Supply Chain, SBOM Generation Tools, JavaScript, Rust
1
Introduction
Software Bill of Materials (SBOMs) are structured inventories of software dependencies, standardized through formats such as SPDX and CycloneDX[12, 18]. They are now widely used as part of software supply chain security practices. A typical usage is vulnerability management: organizations cross-reference their component inventory with public vulnerability databases to identify known threats.
RQ1 What is the coverage of Syft, Trivy and cdxgen on JavaScript and Rust projects, and how does it vary across dependency scopes? RQ2 What mechanisms generate divergences between tool output and the lockfile baseline, including on complex 1
Alan Prado, Olivier Zendra, Philippe Boinot, and Olivier Barais
2.2
structures such as monorepos and multi-lockfile projects, and what is their nature: representation difference, design choice, or tool error? RQ3 How completely does each tool populate the fields a specification-compliant SBOM consumer would expect? To answer our research questions, we built a dataset of 2,050 JavaScript and 1,276 Rust projects from GitHub, archived via Software Heritage [22]. We generated SBOMs with three widely used tools, Syft [1], Trivy [2], and cdxgen [17], and compared their output against our lockfile-based reference. We then applied a normalization pipeline to classify each divergence as a representation difference (same dependency, different encoding), a design choice (deliberate tool behavior), or a tool error. Our results show that Syft and Trivy cover only 43.78 % and 32.71 % of JavaScript dependencies, but reach 100 % and 83.85 % on Rust. The tool cdxgen performs well in both ecosystems, achieving 98.72 % to 99.91 % coverage in JavaScript and 99.34 % to 100 % in Rust. When no lockfile is available, Trivy and Syft produce an empty SBOM. Our analysis also shows that most divergences are explainable, while some reflect understandable but incompatible design choices between tools. Beyond coverage, completeness for some specification fields also varies across tools. Together, these findings raise important questions for SBOM standardization, especially in the context of the CRA deadlines. The rest of this paper is organized as follows. Section 2 reviews related work. Section 3 describes our dataset, reference, and normalization pipeline. Section 4 presents our results. Section 5 discusses our work and its limitations. Section 6 concludes and sketches future work.
2
2.3
Limitations in Component and Dependency Extraction.
While SBOM generation capabilities have significantly expanded, compliance requires more than merely producing an SBOM document: the generated inventory must be accurate, complete, interoperable, and representative of the actual software composition. Consequently, weaknesses in dependency extraction, component identification, and SBOM interpretation become critical challenges as organizations increasingly rely on automated SCA pipelines to satisfy emerging regulatory expectations. However, recent studies have highlighted several limitations affecting the reliability, interoperability, and completeness of current SCA solutions. 2.3.1 Component Identification. A first category of limitations concerns the accuracy of component identification. Several studies [20, 24, 25] report that SCA tools frequently fail to correctly extract component metadata, particularly package names and versions, leading to incomplete or incorrect SBOM entries. These identification errors directly and adversely affect downstream vulnerability analysis, since inaccurate component inventories may prevent the detection of vulnerable dependencies or, conversely, generate incorrect security alerts.
Background & Related Work
Software Composition Analysis (SCA) tools have become a central element of modern software supply chain security, by providing Software Bill of Materials (SBOMs), i.e., inventories of third-party components and their associated metadata written in standardized formats such as CycloneDX [18] or SPDX [12]. This enables enhancing software transparency and identification of third-party components, their dependencies, and associated vulnerabilities.
2.1
Tooling Ecosystem.
However, the rapid shift from voluntary adoption to regulatory requirements regarding SBOMs has led to the emergence of a vast ecosystem of tools supporting software supply chain security activities. Existing solutions cover various stages of the SBOM lifecycle, including generation, usage, validation, transformation, and interoperability. This analysis shows that SBOM generation remains the predominant use case, with 54 tools (64%) offering generation capabilities, while standardization and interoperability remain persistent challenges within the ecosystem [13]. Similarly, the "CycloneDX Tool Center" reports a growing number of SBOM related tools with over 288 current listings [19], thereby illustrating the rapid expansion of the SBOM ecosystem.
2.3.2 Complex ecosystems. Another challenge relates to the analysis of complex package ecosystems. Existing SCA approaches often rely on generic dependency extraction mechanisms that struggle with ecosystems where dependency resolution is managed through multiple package managers or language-specific mechanisms. For instance, Python projects involving Poetry, Pipenv, and setuptools introduce additional metadata sources and resolution rules that are not always correctly handled by SCA tools [3, 5]. More generally, several studies [3, 28] argue that multi-language SCA approaches should incorporate the native dependency resolution mechanisms of each programming language, instead of relying exclusively on universal extraction strategies.
Context: Regulatory Drivers.
SBOM adoption has accelerated in recent years due to growing concerns regarding software supply chain security and the emergence of regulatory requirements. In the United States, government and executive initiatives have encouraged SBOM adoption as a security practice for critical software supply chains [9]. Similarly, in Europe, regulatory developments are reinforcing the need for transparent software composition management. The Cyber Resilience Act (CRA) [8], in particular, introduces cybersecurity obligations for products with digital elements, including requirements regarding vulnerability management, secure development practices, and software components transparency. Under these obligations, manufacturers are required to maintain accurate information on the software components integrated into their products, thereby increasing the importance of reliable SBOM generation and analysis.
2.3.3 Weak Dependency analysis. Dependency analysis itself remains a major source of inaccuracies. Multiple studies identify problems in the reconstruction of dependency graphs, including inconsistent dependency tree roots [20] and incorrect exploration of transitive dependencies across ecosystems such as JavaScript, Rust, and Python [3, 10, 11, 20, 24, 26]. Furthermore, SCA tools may report 2
Mind the Gap: How SBOM Specification Ambiguities Lead to Divergent Software Bills of Materials.
dependencies that are declared but unused, commonly referred to as bloated dependencies [20]. Conversely, they may include build-time, testing, or environment-specific dependencies, introducing false positives and contaminating the generated SBOM with components that are not part of the deployed application [21, 24].
reflected in the TIOBE Index, where Rust recently climbed to 12th place 1 . Another reason for selecting these two languages is that both ecosystems use dependency manifest files and lockfiles, making it possible to analyze dependency declarations and the mechanisms used to ensure reproducible dependency resolution.
2.3.4 Syntactic Correctness and Parser Robustness. Beyond dependency extraction, related work highlights structural vulnerabilities regarding SBOM correctness. Specifically, current SCA tools may generate malformed documents or fail unexpectedly when processing syntactically valid SBOMs [10, 11]. Such discrepancies in parser implementation not only hinder interoperability but also open the door to security risks, including parser confusion attacks [26].
3
3.1.2 Project Selection. We queried the GitHub Search API to retrieve popular repositories in Rust and JavaScript, sorted by star count in descending order, with a lower bound of 1,000 stars. We restrict our dataset to projects providing at least one manifest file (package.json for JavaScript and Cargo.toml for Rust) declaring at least one dependency. Projects for which a fresh installation could not produce a lockfile are excluded from the dataset, as described in the dataset paragraphs below.
Methodology
Previous work shows that current Software Composition Analysis (SCA) solutions still face fundamental challenges in accurately identifying software components, reconstructing dependency relationships, producing interoperable SBOMs, and maintaining consistent interpretations across tools, often generating different SBOMs when analyzing the same source code. In this paper, we investigate the factors that cause different tools to produce distinct SBOMs from identical inputs. To better understand the origin of these discrepancies, we deliberately narrow the scope of our study by:
3.1.3 Archiving and reproducibility. To ensure strict control over the projects under study, each selected project was matched against Software Heritage (SWH), a universal source code archive that stores repository snapshots as an immutable Merkle graph. Each revision is identified by a unique SWHID id (which is derived from the SHA-1 hash of the content tree) [23], guaranteeing that two independent analyses of the same identifier will examine exactly the same repository state. Only projects that had been archived by SWH at least once were retained. The revision corresponding to the most recent archival snapshot was selected.
• considering only source code repositories; • excluding dynamic dependencies and runtime dependency resolution mechanisms.
3.1.4 JavaScript dataset. We collected 2,105 JavaScript projects. Rather than relying on lockfiles committed by developers, which may be desynchronized from the manifest or simply absent, we regenerated a fresh lockfile for every project in our dataset. To do so, we first had to determine which package manager to invoke: we inferred it from the existing lockfile when one was present in the repository (npm, Yarn, or pnpm), and otherwise consulted the packageManager field in package.json, falling back to npm by default. This freezing step also allowed us to exclude projects that could not be installed. After this step, 2,050 projects had a successfully generated lockfile, failures being primarily due to yanked packages or unsatisfiable dependency constraints, and constitute our final dataset for JavaScript.
Furthermore, we focus on projects that provide dependency manifests and, additionally, lockfiles (e.g., yarn.lock, pnpm-lock.yaml, and Cargo.lock). These artifacts allow us to establish a groundtruth dependency oracle, serving as a baseline for evaluating the accuracy of the generated SBOMs. By controlling these variables, we aim to identify the factors that lead tools to report different dependency inventories despite analyzing identical source code. This section now describes how we collected the dataset, generated SBOMs, extracted the lockfile baseline, and compared tool output against it.
3.1
3.1.5 Rust dataset. We collected 1,361 Rust projects. Rather than relying on Cargo.lock files committed by developers, which may be desynchronized from the manifest or simply absent, we performed a fresh cargo fetch for each project to generate a new Cargo.lock. This freezing step also allowed us to exclude projects for which the root installation failed. After this step, 1,276 projects had a successfully generated Cargo.lock, failures being primarily due to yanked packages or unsatisfiable dependency constraints, and constitute our final dataset for Rust.
Dataset
3.1.1 Language Selection. We choose two different programming languages: JavaScript and Rust. • JavaScript has the largest and most interconnected package ecosystem in the world, largely due to its micro-package philosophy. It is also a prime target for dependency confusion attacks, typosquatting, and malicious package injection. Furthermore, the JavaScript ecosystem is fragmented across several major package managers, including npm, Yarn (Classic v1 and Berry v2+), and pnpm. • Rust can be considered the opposite of JavaScript in this regard. It has gained considerable popularity thanks to its emphasis on memory safety, high performance, and a developer-friendly experience [4]. Large technology companies are increasingly adopting Rust to build secure, robust, and scalable software systems. This growing adoption is
3.1.6 Lockfile-Based Reference. The goal is to establish a baseline against which the output of the SBOM generation tools can be compared. We cross-compare each tool’s output against this baseline to identify which dependencies are missing from each tool’s SBOM, and which are reported in addition to the baseline. Building this baseline requires parsing the lockfiles generated during the 1 https://www.tiobe.com/tiobe-index/
3
Alan Prado, Olivier Zendra, Philippe Boinot, and Olivier Barais
freezing step (Section 3.1), since they contain the exact, resolved set of dependencies produced by a fresh installation, independent of what developers originally committed. We built parsers for all lockfile formats in our dataset: npm package-lock.json in three versions (v1, v2, v3) plus npm-shrinkwrap.json (a v1-equivalent), Yarn v1 and Berry, pnpm v5, v6 and v9 (v7 and v8 share the v6 format), and Cargo.lock v1/v2/v3. Each package is annotated with its dependency type: production, development, optional, peer, or build (Rust). Our parser extracts all dependencies present in the lockfile without filtering by type, to remain exhaustive. This allows us to compare and understand potential differences in tool behavior.
3.2.2 Campaigns Design. For each ecosystem (JavaScript and Rust), we define three campaigns varying the dependency information available to the tools at generation time, for a total of six campaigns. The first campaign assesses tool behavior in the manifest-only setting (Section 3.1.7), when only manifest files are available. The remaining two campaigns are lockfile-based. They rely on the same frozen dataset (Section 3.1) and differ only in the lockfiles made available to the tools during SBOM generation. The clean_root method exposes only the root lockfile, making it the only available lockfile reference, while temporarily removing lockfiles located in subdirectories. Conversely, the clean_deep method exposes all lockfiles present in the frozen snapshot, including both root and subdirectory lockfiles. These two campaigns evaluate how SBOM generators behave under different levels of dependency visibility and lockfile completeness.
3.1.7 Manifest-Only Setting. To assess tool behavior when no pinned dependency tree is available, we additionally run SBOM generation tools on every project in the dataset after removing all lockfiles, leaving only the manifest file (package.json or Cargo.toml). This setting is applied uniformly across the entire dataset, so that every project can be analyzed under both conditions, lockfile-based and manifest-only, and compared on a per-project basis. The reference baseline used for comparison differs by ecosystem. For Rust, cdxgen analyzes Cargo.toml statically without performing any installation; the frozen Cargo.lock generated during the freezing step (Section 3.1) thus serves directly as the reference, as no temporal drift can occur. For JavaScript, cdxgen performs a dynamic npm install at analysis time; to ensure temporal comparability, we perform a concurrent fresh installation for each project and use the resulting lockfile as the reference baseline. This avoids biases introduced by version drift between a pre-generated frozen lockfile and cdxgen’s runtime resolution. We then compare the SBOM produced by each tool under the manifest-only setting against this reference to quantify the gap between the actual dependency tree and what each tool reports when only the manifest is available.
3.2
3.3
Detection and Normalization Pipeline
A naive comparison between SBOM output and lockfile content counts many apparent mismatches that are not actual errors, since the same dependency can be represented differently depending on the tool. Before computing any metric, we apply a normalisation pipeline that aligns these representations so that identical dependencies are recognised as such by our experimental framework, regardless of how each tool expresses them. This pipeline operates only on the data extracted for comparison, never on the SBOM artefacts themselves, and no information is discarded: each normalisation is recorded, which makes it possible to trace what diverges and why. Beyond alignment, the pipeline also allows identifying the nature of differences that persist after normalisation: a representation difference, where both sides refer to the same dependency but express it in distinct forms, a design choice, where the tool makes a deliberate decision that diverges from the baseline, or a tool error, where the tool output is simply incorrect, reporting a component that cannot be traced back to any real dependency.
Experimental Setup
3.2.1 Tools. We selected three SBOM generation tools: Syft v1.38.2 [1], Trivy v0.68.2 [2], and cdxgen v12.0.0 [17]. These versions were pinned to ensure experimental reproducibility. Syft and Trivy were selected due to their frequent use in recent empirical SBOM studies, their support for the ecosystems considered in this work, and their adoption in DevSecOps workflows. cdxgen was included as a representative SBOM generator from the CycloneDX ecosystem. All three tools are configured to produce output in CycloneDX 1.6 JSON format.
3.4
Metrics
We measure three quantities for each tool and campaign. Coverage is the fraction of lockfile packages reported by the tool, computed separately for the full dependency set, production dependencies only, and development dependencies only. It corresponds to recall against the lockfile baseline, and is reported as a per-project mean across all contributing projects in a campaign. Extra packages are packages reported by the tool but absent from the lockfile. They are counted per project and per tool, and examined qualitatively to identify their cause. Divergences are the points where tools disagree with one another, as identified by the normalisation pipeline. They are recorded and quantified, providing a data source on the precise packages where tools differ and on the reasons behind these discrepancies. All metrics are computed after applying the normalisation pipeline described in Section 3.3.
For lockfile-based campaigns, cdxgen is invoked with the --noinstall-deps option to prevent additional dependency resolution and ensure that generated SBOMs reflect only the information available from the frozen lockfile. Although the presence of a frozen lockfile should normally prevent dependency reconstruction, this option provides an additional safeguard against implicit installation or resolution steps performed by the tool. This flag is disabled in the manifest-only setting (Section 3.1.7), where no lockfile is available and cdxgen ’s dependency resolution capabilities are explicitly evaluated. 4
Mind the Gap: How SBOM Specification Ambiguities Lead to Divergent Software Bills of Materials.
and 99.34 % on Rust under clean_deep (99.91 % and 100 % under clean_root), though not quite reaching 100 %, a residual gap we trace below. Syft and Trivy both exhibit a sharp ecosystem-dependent inversion, though with different magnitudes. Under clean_deep, Syft reports only 43.78 % of lockfile packages on JavaScript projects, yet reaches 100 % on Rust projects (42.75 % and 100 % under clean_root). Trivy follows a similar pattern, covering 32.71 % on JavaScript and 83.85 % on Rust under clean_deep (30.25 % and 83.02 % under clean_root).
We investigated cdxgen’s residual gap and traced it to a hardcoded directory exclusion list in cdxgen 12.0.0. This list includes /examples/, which causes any lockfile located under a directory named exactly examples to be silently skipped, a simple stringmatching rule, not a structural limitation of cdxgen’s dependency resolution. Its effect varies by setting:
Figure 1: Average SBOM coverage against the lockfile baseline, JS corpus.
• Rust: this rule, together with a few related exclusions (docs/, tests/, .github/), explains 100 % of cdxgen’s missing packages under clean_deep, affecting a small number of multi-crate projects (sea-orm, cargo-leptos, trunk). • JavaScript: the rule explains some, but not all, of the lockfiles cdxgen never captured under clean_deep. • clean_root: the rule never triggers, since exposing only the root lockfile means no lockfile can ever sit under an examples/ subdirectory, which is why cdxgen’s scores are higher there. In the manifest-only setting, that is, when projects are submitted without any lockfile, we observe two different behaviors across languages. For JavaScript, cdxgen attempts to install dependencies to generate a lockfile and report the full dependency graph; when the installation succeeds, the dependencies reported in its SBOM closely match those produced by our own installation, though we observe minor gaps for a small number of projects. For Rust, cdxgen behaves differently: it performs no installation and only reads the manifest, so it naturally cannot report transitive dependencies. Moreover, even within the manifest, it does not report all declared dependencies, notably missing those declared as dev or build dependencies. Furthermore, the reported versions are not pinned, they are the version specifiers from the manifest rather than the resolved versions from a lockfile, meaning they do not match our lockfile-based baseline. Compared to this baseline, cdxgen therefore only reaches a coverage of 3.2%. For Trivy and Syft, the behavior is the same across both ecosystems: without a lockfile, both tools produce an empty SBOM, as they require a resolved lockfile to enumerate components and do not perform automatic installation.
Figure 2: Average SBOM coverage against the lockfile baseline, Rust corpus.
4
Results
This section presents the results of our empirical evaluation. We first report coverage across tools and ecosystems (RQ1), then analyze the sources of divergence between tool output and the lockfile baseline (RQ2) and finally assess how completely tools populate expected fields for the components they do report (RQ3).
4.1
RQ1: Coverage Across Tools and Ecosystems and variation across dependency scopes
We address this research question through the two lockfile-based campaigns introduced in Section 3, clean_root and clean_deep, which share the same frozen corpus and differ only in the scope of lockfiles exposed to the tools at SBOM generation time. Figures 1 and 2 report the average coverage achieved by each tool under these two campaigns, for JavaScript and Rust respectively, computed after applying the normalization pipeline (Section 3.3). The tool cdxgen performs consistently well across both ecosystems and both installation scopes, reaching 98.72 % on JavaScript
Overall, these results confirm that the presence of a lockfile is a key determinant of SBOM completeness. However, even in the frozen setting, coverage remains imperfect for some tools, and its absence further degrades results, leading to partial (cdxgen) or empty (Trivy, Syft) SBOMs in the manifest-only setting. 5
Alan Prado, Olivier Zendra, Philippe Boinot, and Olivier Barais
4.2
Table 1: Over-reporting mechanisms relative to the lockfilebaseline reference (JavaScript).
RQ2: Mechanisms of Divergence
4.2.1 Scope divergence: devDependencies handling. Syft and Trivy both exhibit an abnormally low JavaScript coverage, as both exclude devDependencies from their SBOM, but not in the same way. In Syft, the exclusion is a design choice applied inconsistently depending on the package manager used, while in Trivy, the exclusion is enabled by default but an implementation error causes it to partially fail, letting some transitive dependencies through. Syft’s inconsistency is package-manager-dependent: in the npm project js-framework-benchmark, it reports 100% of production dependencies (2249/2249) but excludes devDependencies entirely (0/4930). In the Yarn project chakra-ui-vue and the pnpm project ember.js, by contrast, it reports both dependency types at 100% (3164/3164 and 28/28 for chakra-ui-vue; 372/372 and 1724/1724 for ember.js), applying no distinction at all between production and development dependencies for these two formats. The same inconsistency appears in Rust: Syft reports devDependencies present in Cargo.lock despite applying exclusion logic elsewhere. This is not a bug in the traditional sense, but a design choice that has never been applied uniformly across the formats Syft supports.
Example
cdxgen cdxgen Trivy
[email protected] (fast-xml-parser) [email protected] (alt) react-native-root-toast
Total 786 650 557
4.2.2 Over-reporting mechanisms relative to the lockfile-based baseline. Beyond exclusion mechanisms, cdxgen and Trivy also report components that fall outside our lockfile-based baseline by design, through three distinct detection mechanisms summarized in Table 1. Filename-based detection. cdxgen’s filename-based detection heuristic scans all files in the project independently of any lockfile or manifest, applying a regular expression to filenames to identify a <name>-<version> pattern. The resulting component is tagged with the filename detection technique and the lowest confidence score on cdxgen’s scale (0.25, versus 1.0 for a lockfile-derived entry or 0.7 for a manifest entry), explicitly signaling the absence of any verification against a registry or declared entry. This mechanism specifically targets vendored code, libraries manually copied into the project without going through a package manager. The heuristic is not perfect: in some cases, it incorrectly detects version-like elements embedded in source code comments, producing invalid entries such as for@license, which cannot be mistaken for real dependencies but still increase the component count. bower.json parsing. bower.json is an older JavaScript manifest format used for frontend dependencies before the widespread adoption of npm. cdxgen actively parses bower.json as a fullyfledged declaration source, on par with package.json, and extracts the declared name and version with the same reliability. This is therefore not a detection reliability issue, but a scope issue: bower.json predates modern lockfiles and was never part of our baseline, which is limited to lockfile formats. bun.lock parsing. The bun.lock lockfile format, used by the Bun package manager, constitutes a third source of divergence. Some corpus projects include a bun.lock alongside an npm lockfile; Trivy detects and parses it directly, tagging the resulting components as bun-typed, while Syft and cdxgen do not read it. Since bun.lock is not part of our baseline, only bun-typed components that do not already appear in a recognized lockfile are counted.
the entire subtree should be excluded from the SBOM
[email protected] devDependency
[email protected] optionalDependency
What Trivy produces (SBOM) [email protected] attached directly to root package
root package
[email protected] prod, other package
Tool
Filename-based detection bower.json parsing bun.lock parsing
Trivy does exclude [email protected], but not [email protected]. 0, which ends up attached directly as a root node in the dependencies section of its SBOM, as though it were a top-level dependency, rather than being excluded along with its parent. The exclusion thus stops at the first level (the package directly marked as dev), without propagating to its transitive dependencies, as shown in Figure 3.
Expected structure (lockfile)
[email protected] prod, other package
Mechanism
[email protected] orphaned
Figure 3: Orphaned node produced by Trivy on a Yarn lockfile project : the excluded dependency’s child is incorrectly attached directly to the root package. Trivy’s divergence is of a different nature: the tool excludes development dependencies by default, but the exclusion logic is faulty. This malfunction manifests in Yarn lock files, as illustrated by the GooglePlayMusicDesktopPlayer project. In the lockfile, [email protected] is a direct development dependency (parent: [email protected]), and one of its dependencies, [email protected], is declared as an optionalDependency of escodegen, not as a devDependency itself, but it inherits its parent’s dev status since [email protected] is not reachable through any other path. Neither should therefore appear in the SBOM.
4.2.3 Identifier representation divergence. Unlike the mechanisms above, the following phenomena do not reflect errors relative to the baseline, but representational choices that complicate cross-tool matching: the same real-world component may be reported under different identifiers depending on the tool. Table 2 summarizes these mechanisms. 6
Mind the Gap: How SBOM Specification Ambiguities Lead to Divergent Software Bills of Materials.
Table 2: Identifier representation divergences (JavaScript).
Package aliasing. Some lockfile entries use a key of the form alias@npm:real-package@version, where the alias and the real registry name coexist in the same entry. For example, in the spectrum project, the alias react-dom points to the real package @hot-loader/[email protected]. When tools differ in the name they report, the resulting PURLs diverge, causing the same component to appear as two distinct entries across SBOMs. In the example above, cdxgen and Trivy report the alias react-dom, while Syft reports the real scoped name @hot-loader/react-dom. Our pipeline normalizes all reported names to the real npm package name extracted from the lockfile. Peer-dependency suffixes. In pnpm v5/v6 lockfiles, the snapshot key encodes peer dependency context directly into the version string, for example, in the eslint-plugin-prettier project, @graphql-tools/[email protected][email protected], where [email protected] is the resolved peer dependency context, not part of the actual version. cdxgen and Syft report the raw suffixed version instead of @graphql-tools/[email protected], producing a different PURL, whereas Trivy handles this case correctly. Symlink resolution. In some lockfiles, the same package appears under two distinct entries: a symlink entry (marked link: true) pointing to the source, and an actual source entry carrying the version. Syft indexes both entries, which produces an additional UNKNOWN component in the SBOM for the symlink entry, since it carries no version. In the robot project, the lockfile entry node_modules/lit-robot is a link to packages/lit-robot, which carries the real version 3.0.0: Syft’s SBOM contains both lit-robot@UNKNOWN (symlink entry) and packages/lit-robot@ 3.0.0 (actual source entry). This mechanism is Syft-specific. Monorepo and vendor path prefixes. Syft reports packages with their full path (packages/X, vendor/X) whereas the other tools only report the basename, leading to divergent PURLs for the same component. This is precisely what happens to the resolved entry above, Syft reports packages/lit-robot instead of lit-robot even once the version is correctly identified. A second example, in project shields, shows Syft reporting vendor/http-deceiver instead of http-deceiver. Hash, URL, and semver mismatches. When a dependency is pinned to a git or tarball reference rather than a standard registry release, a tool may report that raw reference instead of the actual semantic version recorded in the same lockfile entry. For example, in the v2.cn.vuejs.org project, the dependency hexo-generator-alias is pinned to a GitHub fork at commit 67adb814..., with real version 0.1.3: cdxgen reports the commit hash (hexo-generator-alias@ 67adb814a76750f3c841825f955bd5dd92cd1f20), Syft reports the full tarball URL (https://codeload.github.com/chrisvfritz/vuejs. org-hexo-generator-alias/tar.gz/67adb814...), and Trivy reports the semantic version [email protected]. Yarn workspace placeholders. Syft relies exclusively on the lockfile: on Yarn Classic, which never records local workspace members in yarn.lock, the member is simply absent from the SBOM; on Yarn Berry, which does write a 0.0.0-use.local stub, Syft reports that placeholder verbatim. By contrast, cdxgen actively resolves the real version from the member’s own package.json,
Mechanism Package aliasing pnpm peer-suffix Symlink resolution Path prefixing
cdxgen
trivy
syft
Total
412 104 — —
104 0 — —
64 104 755 305
580 208 755 305
regardless of whether Yarn Classic leaves no trace or Yarn Berry writes a placeholder, consistently across the dataset. 4.2.4 Structural divergence: root component and dependency graph topology. Beyond individual component discrepancies, tools also diverge in how they represent the root package and structure the overall dependency graph, a phenomenon observed in both JavaScript and Rust. Root package handling differs across tools. The tool cdxgen includes the root package in metadata.component. Trivy only mentions the project path in metadata.component, similar to Syft. Trivy also adds a dependency that is simply the lockfile itself. In JavaScript, the three tools produce three distinct topologies, illustrated in Figure 4. Trivy follows a three-level hierarchy: the scanned project directory is the top-level metadata. component, which depends on one or more lockfile components (e.g., package-lock.json) acting purely as provenance anchors, each in turn depending on the harvested packages. Syft also declares the project directory as metadata.component, but, unlike Trivy, never surfaces it as a root node in the dependencies section; instead, it introduces a separate lockfile-root component, taken from the lockfile’s own header, which anchors the harvested packages. cdxgen declares every lockfile’s root package under metadata.component (nesting secondary ones under metadata.component.components), and uses their bom-ref values directly as root nodes in the dependencies section. In Rust, the three topologies converge more closely: all three tools surface the root package in the components section, but Trivy and cdxgen each add one extra node relative to Syft. Trivy turns the root crate into a genuine intermediate node rather than a mere provenance anchor, producing a four-level hierarchy (project directory, Cargo.lock, root crate, dependencies) instead of three. cdxgen lists the root crate twice, once as metadata.component and once as a components-section entry sharing the same bom-ref. Syft’s behavior is unchanged from JavaScript.
4.3
RQ3: Spec Completeness
RQ1 and RQ2 ask whether tools capture the right components. This section asks a different question, evaluated directly on the produced SBOMs rather than on the subset of components that match the lockfile baseline reference: does the SBOM populate the fields that a specification-compliant consumer would be entitled to expect? We measure this against the NTIA’s minimum elements (Supplier, Component Name, Version, Other Unique Identifiers, Dependency Relationship, Author of SBOM Data, Timestamp), together with three additional CycloneDX fields that vary widely across tools in 7
Alan Prado, Olivier Zendra, Philippe Boinot, and Olivier Barais
Trivy
Syft
cdxgen
metadata.component project dir
metadata.component project dir
metadata.component primary root pkg
.components[] other root pkgs
not in dependencies package-lock.json provenance anchor
pkg-A
pkg-B
lockfile root pkg name+version from header
pkg-C
pkg-A
pkg-B
pkg-A
pkg-B
pkg-C
pkg-C
Legend: metadata.component
lockfile / root pkg
harvested package
not in dependencies
Figure 4: Dependency graph structure in the dependencies section across Trivy, Syft, and cdxgen (JavaScript). Table 4: Spec completeness (Rust, rust_clean_deep)
practice: licenses, hashes, and external references. CISA’s 2025 update to the minimum elements, a public comment draft at the time of writing [6], notably promotes License and Component Hash to formal minimum elements in their own right [6], which reinforces the relevance of examining these two fields alongside the original NTIA set. Tables 3 and 4 report these rates under clean_deep for JavaScript and Rust respectively. Component name, version, unique identifiers (PURL or CPE), dependency relationships, and timestamp are populated by all three tools on both ecosystems at 99.7 % or above, we therefore focus below on the fields that diverge sharply. Table 3: Spec completeness (JS, js_clean_deep)
Field
cdxgen
Syft
Trivy
Component name Version PURL CPE Supplier Licenses Hashes External references Dependency relationships Timestamp Author of SBOM data, strict Tool Name Generation context
100.0% 100.0% 100.0% 0.0% 0.0% 75.8% 98.2% 0.0% 100.0% 100.0% 100.0% 100.0% 100.0%
100.0% 100.0% 100.0% 100.0% 0.0% 60.2% 0.0% 0.0% 99.7% 100.0% 0.0% 100.0% 0.0%
100.0% 100.0% 100.0% 0.0% 0.0% 0.0% 0.0% 0.0% 100.0% 100.0% 0.0% 100.0% 0.0%
Field
cdxgen
Syft
Trivy
Component name Version PURL CPE Supplier Licenses Hashes External references Dependency relationships Timestamp Author of SBOM data, strict Tool Name Generation context
100.0% 100.0% 100.0% 0.0% 0.0% 0.0% 97.8% 0.0% 100.0% 100.0% 100.0% 100.0% 100.0%
100.0% 100.0% 100.0% 99.9% 0.0% 0.0% 0.0% 97.5% 100.0% 100.0% 0.0% 100.0% 0.0%
100.0% 100.0% 100.0% 0.0% 0.0% 0.0% 0.0% 0.0% 100.0% 100.0% 0.0% 100.0% 0.0%
single pattern common to all four: the CPE component of unique identifiers and hashes split along tool lines, each populated almost exclusively by one tool, though not the same tool for both; licenses split instead along ecosystem lines; and external references vary by both tool and ecosystem simultaneously (Tables 3 and 4). The Author of SBOM Data field, in the strict NTIA sense, is populated only by cdxgen; Syft and Trivy leave it empty, although the identity of the generating tool can still be recovered through other SBOM metadata in all three cases (a tool-fallback measure we compute separately, at 100 % for all three), a distinction CISA’s 2025 draft now formalizes as two separate elements, SBOM Author and Tool Name [6], the latter matching exactly what our tool-fallback measure captures. CISA’s 2025 draft also introduces Generation Context as a new minimum element, recording the software lifecycle phase (before, during, or after build) at which the SBOM was generated [6]; only cdxgen populates it (always tagged pre-build),
The clearest gap concerns the Supplier field, populated by none of the three tools on either ecosystem (Tables 3–4); CISA’s 2025 draft renames this element Software Producer and sharpens its definition to the entity that produces the software itself, as opposed to a distributor [6], making the gap even harder to fill from SBOM metadata alone. The remaining divergent fields show no 8
Mind the Gap: How SBOM Specification Ambiguities Lead to Divergent Software Bills of Materials.
leaving consumers of Syft or Trivy SBOMs with no way to tell, from the SBOM alone, what kind of artifact was analyzed.
5
5.1.2 Origin of dependencies. A source of divergence concerns how components are discovered. Our RQ2 results show tools relying on markedly different sources: lockfiles, manifests, filenames of vendored code, or alternative lockfile formats such as bower.json and bun.lock (Section 4.2). Given the diversity of programming languages and package management ecosystems, standardizing the discovery heuristics themselves is inherently complex; what can and should be standardized, however, is the way their outcome is recorded. We suggest that provenance tagging become a standardized, cross-tool attribute rather than one tool’s internal convention. This would let consumers distinguish components that are explicitly declared from those merely inferred by heuristics of varying reliability.
Discussion
Our results show that the divergences documented in prior work are, for the most part, neither random nor mysterious: they trace back to identifiable design choices and representation differences (RQ1, RQ2), rather than to chance. RQ3 reveals a separate, independent problem: the fields a spec-compliant SBOM consumer would expect are populated inconsistently across tools, and for at least one mandatory field, never at all. Solving the coverage and representation problems would not, by itself, be enough to produce a compliant SBOM.
5.1
5.1.3 Dependency graph structure. A source of divergence concerns the representation of the root component and the dependency graph itself. Our structural findings (Section 4.2) show the three tools adopt three distinct topologies for the same JavaScript project, and a further split on Rust, which reduces interoperability with downstream SCA tooling and complicates cross-tool comparison. Consequently, we advocate for future revisions of SPDX and CycloneDX to define a canonical graph structure, specifying, at minimum, how the root component is identified.
SBOM and tools limitations
Stepping back, the coverage and mechanism divergences documented in RQ1 and RQ2 share a common root cause: the demand placed on SBOM generation tools is not precise enough. Current SBOM standards, including CycloneDX and SPDX, provide detailed guidance on how a dependency should be represented once selected, but do not precisely define which dependencies should be included in the first place. To improve interoperability and enable reproducible comparisons between SBOM generation tools, we believe that several aspects of SBOM generation deserve further standardization.
Beyond these standardization gaps, our results also surface concrete near-term risks for CRA compliance. The Cyber Resilience Act (CRA) turns SBOM generation from a voluntary security practice into a compliance obligation, and in practice this obligation will overwhelmingly be discharged using widely available open-source generators such as the three studied here. Our RQ1 results show (Section 4.1) that this is not a neutral choice: depending on whether a JavaScript publisher generates its SBOM with Syft, Trivy, or cdxgen, the resulting inventory’s completeness varies substantially depending on which tool a JavaScript publisher uses. A publisher who follows the letter of the regulation by producing an SBOM has no straightforward way to know whether they have produced a complete one.
5.1.1 Scope of dependencies. A source of divergence concerns which dependency types are in scope (production, development, test, documentation, optional, peer, or workspace), a divergence we document directly in our devDependencies findings (Section 4.2). Tobar et al. [24] and Rabbi et al. [21] present build-time, testing, or environment-specific dependencies as a source of false positives, arguing that they contaminate the generated SBOM with components that are not part of the deployed application. In our work, we deliberately do not adopt this filtering perspective: we consider build, test, development, and runtime dependencies as all valuable when generating SBOMs, and argue that both a development SBOM and a deployment SBOM are relevant, complementary artifacts, capturing two distinct moments of the software lifecycle. The former exposes the full dependency surface accessible to contributors and CI/CD pipelines, relevant when reasoning about supply-chain attacks targeting build or test tooling, while the latter reflects the actual attack surface of the application as it runs in production. Consequently, what is considered a "false positive" in the context of a deployment SBOM may constitute legitimate, security-relevant information in the context of a development SBOM. Indeed, development dependencies remain critical for assessing supply-chain risk and have themselves been the target of supply-chain attacks [7, 16, 27]. This is precisely why our lockfile baseline deliberately includes components originating from test directories and fixtures, as well as buildtime and development dependencies, rather than being restricted to runtime/production-only components. Rather than leaving this choice to each tool discretion, SBOMs could record each component scope through a standardized attribute, making filtering an explicit, auditable step rather than a default behavior.
5.1.4 Lockfile vs. manifest. A more severe version of this problem occurs when a project has no lockfile at all, a common case for libraries, which often exclude package-lock.json or Cargo.lock from version control. In this manifest-only case, Trivy and Syft do not just under-report: they produce an empty SBOM, with no error or warning shown to the operator. cdxgen avoids this problem for JavaScript by trying to install the project and build a full dependency graph, though the install does not always succeed, but not for Rust, where it just reads the manifest file directly. This means it only reports unpinned, direct dependencies. A publisher whose repository policy leaves out lockfiles, whether on purpose or by mistake, would therefore get an SBOM that looks plausible but is actually empty or badly incomplete from two of the three tools we test, and a partial one from the third, depending entirely on which ecosystem the project uses. 5.1.5 Dependency identifiers. A second, independent exposure arises even when a dependency is correctly detected. The identifierrepresentation divergences, an npm alias reported under its alias rather than its real registry name, a pnpm peer-dependency suffix left in the version string, the same lockfile entry reported at times as 9
Alan Prado, Olivier Zendra, Philippe Boinot, and Olivier Barais
a git commit hash, at times as a URL, at times as a semantic version, result in different PURLs being generated. Since vulnerability analysis tools rely on these identifiers to correlate software components with known vulnerabilities, discrepancies in generated PURLs may lead to different analysis outcomes depending on the identifier being used. Such discrepancies could potentially undermine the effectiveness of the primary use case (vulnerability management) that motivates the adoption of SBOMs under the CRA. Under this reading, tool choice is no longer just an engineering decision, it is a compliance-exposure question that publishers, or anyone generating an SBOM, currently have no practical way to evaluate. Our work provides a first step towards a method and tool to address this issue.
However, such conclusions can clearly be considered more as fuel for test cases, to assess the quality of upcoming tools and versions. 5.2.3 Field presence versus field correctness. RQ3 measures whether a given specification field is populated, not whether its content is correct. A component whose licenses field is non-empty is counted as compliant in our measurement, even if the reported license is incorrect; the same applies to hashes, external references, and the other fields in Tables 3 and 4.
6
5.1.6 SBOM fields. A third, distinct gap concerns the SBOM’s content itself, independent of which components it lists. The fields a specification-compliant SBOM consumer would expect are populated unevenly across tools (RQ3): the CPE component of unique identifiers and hashes split along tool lines, each populated almost exclusively by one tool though not the same tool for both, licenses split along ecosystem lines, and external references vary by both tool and ecosystem simultaneously. A publisher therefore does not obtain an SBOM carrying the same information regardless of which tool generated it. The clearest case is the Supplier field: none of the three tools populate it, one of NTIA’s original minimum elements, sharpened in CISA’s 2025 draft update to "Software Producer" [6], on either ecosystem. A publisher relying on any of these tools cannot meet this transparency obligation through automated SBOM generation alone.
5.2
Conclusion
We generated SBOMs with three widely used tools (Syft, Trivy, and cdxgen) over the same corpus of JavaScript and Rust projects, and compared them against a lockfile-based reference. Our key findings are as follows: • Tool coverage diverges substantially (RQ1). The tools disagree substantially on which dependencies they report, and this disagreement worsens, or turns into an empty SBOM, when a project has no lockfile. • Divergences are explainable, not random (RQ2). A large share of the disagreement traces back to specific, identifiable causes rather than chance: deliberate design choices such as excluding devDependencies (a design choice), and representation artifacts such as aliasing, peer-suffixes, or path-prefixing that change a component’s identifier without changing the underlying dependency (a representation difference). • Spec-field completeness is uneven (RQ3). The fields a specification-compliant SBOM is expected to carry are populated unevenly across tools, and at least one mandatory field, Supplier, is never populated at all. • Standardization gaps span scope, origin, and structure. (Section 5.1). Current SBOM standards do not precisely define which dependencies should be included, how their provenance should be recorded, or how the dependency graph should be structured, leaving each choice to individual tools. We argue that scope and origin should each be recorded through standardized, cross-tool attributes, and that SBOM formats should specify a canonical graph structure, rather than leaving these choices to each tool’s default behavior. • Tool choice is a compliance risk. SBOM completeness and content currently depend on which tool is used, not only on the project being scanned, which undermines the transparency and vulnerability-management use cases that motivate SBOM adoption in the first place: a scan run against a tool-reported identifier can silently diverge from a scan run against the true package.
Limitations to our work
5.2.1 Dataset selection. Our dataset is limited to GitHub repositories with at least 1,000 stars, favoring actively maintained, popular projects over the smaller, less curated ones that make up most realworld dependencies. We adopted this threshold as a practical proxy for project maturity: highly-starred repositories are more likely to be well-maintained projects with a Cargo.toml or package.json manifest at the root, which is required for our SBOM generation tools to work (on Rust and JavaScript projects respectively). We do not measure how this affects our coverage figures, and cannot rule out that they would differ on a less popularity-skewed sample. 5.2.2 Durability of tool-specific findings. Our results are tied to specific tool versions (Syft 1.38.2, Trivy 0.68.2, cdxgen 12.0.0), and these tools evolve quickly enough that their behavior can change substantially in a short amount of time. Zhou et al. [28], for instance, validated lockfiles as ground truth for Python, Rust, Ruby, and PHP but excluded JavaScript after finding that the contemporary tool versions they used (Trivy 0.66.0, Syft 1.33.0) produced empty SBOMs for package-lock.json. Using newer versions (Trivy 0.68.2, Syft 1.38.2), we find that neither tool produces empty SBOMs anymore, but both now produce partial SBOMs instead. The contrast with Rabbi et al. [20] and Rabbi et al. [21] points to the same pattern. Conclusions drawn here may thus have a limited shelf life and would benefit from periodic re-evaluation as tools are updated.
This does matter for the CRA: as it enters into force, publishers will rely on exactly these tools to produce their mandated SBOMs, so the tools themselves risk becoming a source of non-compliance that publishers have no way to detect. Future work. Two directions follow directly from this work. First, extending the comparison to additional ecosystems and package 10
Mind the Gap: How SBOM Specification Ambiguities Lead to Divergent Software Bills of Materials.
managers (Python, Java, ...) would help establish whether the mechanisms we identify here, design choices and representation differences, uneven field completeness, generalize beyond JavaScript and Rust, or are ecosystem-specific. Second, and more directly, the divergence cases we catalogued in this paper are not only findings: they are also subtle, controlled, concrete test cases. We plan to turn this catalogue into a benchmark for SBOM generation tools, so that a given tool or version can be checked against each identified edge case individually, rather than relying on unstructured, large-scale comparisons like ours to surface regressions after the fact.
[20] Md Fazle Rabbi, Arifa Islam Champa, Costain Nachuma, and Minhaz Fahim Zibran. 2024. Sbom generation tools under microscope: A focus on the npm ecosystem. In Proceedings of the 39th ACM/SIGAPP Symposium on Applied Computing. 1233–1241. [21] Md Fazle Rabbi, Arifa Islam Champa, and Minhaz Fahim Zibran. 2025. Claim vs. capability: A comparative analysis of the SBOM generation tools for rust projects. In Proceedings of the 40th ACM/SIGAPP Symposium on Applied Computing. 1712– 1720. [22] Software Heritage. 2016. Software Heritage. https://www.softwareheritage.org. [23] Software Heritage. 2025. SoftWare Hash IDentifier (SWHID). https://www. softwareheritage.org/software-hash-identifier-swhid/. [24] David Tobar, Jessie Jamieson, Sasank Vishnubhatla, Mark Priest, and Jason Fricke. 2025. Study Finds Key Causes of Divergence in Software Bills of Materials. In CISA-Sponsored SBOM Harmonization Plugfest, Software Engineering Institute, Carnegie Mellon University. [25] Chengjie Wang, Jingzheng Wu, Hao Lyu, Xiang Ling, Tianyue Luo, Yanjun Wu, and Chen Zhao. 2026. A Large Scale Empirical Analysis on the Adherence Gap between Standards and Tools in SBOM. ACM Transactions on Software Engineering and Methodology (Jan. 2026). doi:10.1145/3788692 [26] Sheng Yu, Wei Song, Xunchao Hu, and Heng Yin. 2024. On the Correctness of Metadata-Based SBOM Generation: A Differential Analysis Approach. In 2024 54th Annual IEEE/IFIP International Conference on Dependable Systems and Networks (DSN). 29–36. doi:10.1109/DSN58291.2024.00018 [27] Nusrat Zahan, Thomas Zimmermann, Patrice Godefroid, Brendan Murphy, Chandra Maddila, and Laurie Williams. 2021. What are Weak Links in the npm Supply Chain? arXiv preprint arXiv:2112.10165 (2021). https://arxiv.org/abs/2112.10165 [28] Li Zhou, Marc Dacier, and Charalambos Konstantinou. 2026. A Reality Check on SBOM-based Vulnerability Management: An Empirical Study and A Path Forward. In Proceedings of the Sixteenth ACM Conference on Data and Application Security and Privacy. ACM, 255–268. doi:10.1145/3800506.3803490
References [1] Anchore. 2021. Syft: CLI Tool for Generating SBOM. https://github.com/anchore/ syft. [2] Aqua Security. 2019. Trivy: Security Scanner. https://github.com/aquasecurity/ trivy. [3] Giacomo Benedetti, Serena Cofano, Alessandro Brighente, and Mauro Conti. 2024. The Impact of SBOM Generators on Vulnerability Assessment in Python: A Comparison and a Novel Approach. arXiv:2409.06390 [cs.CR] https://arxiv. org/abs/2409.06390 [4] William Bugden and Ayman Alahmar. 2022. Rust: The Programming Language for Safety and Performance. arXiv:2206.05503 [cs.PL] https://arxiv.org/abs/2206. 05503 [5] Serena Cofano, Giacomo Benedetti, and Matteo Dell’Amico. 2024. SBOM Generation Tools in the Python Ecosystem: an In-Detail Analysis. arXiv:2409.01214 [cs.CR] https://arxiv.org/abs/2409.01214 [6] Cybersecurity and Infrastructure Security Agency. 2025. 2025 Minimum Elements for a Software Bill of Materials (SBOM). (aug 2025). Public comment draft. [7] Ruian Duan, Omar Alrawi, Ranjita Pai Kasturi, Ryan Elder, Brendan Saltaformaggio, and Wenke Lee. 2021. Towards Measuring Supply Chain Attacks on Package Managers for Interpreted Languages. In Network and Distributed System Security Symposium (NDSS). https://arxiv.org/abs/2002.01139 [8] European Parliament and Council of the European Union. 2024. Regulation (EU) 2024/2847 of the European Parliament and of the Council of 23 October 2024 on Horizontal Cybersecurity Requirements for Products with Digital Elements and Amending Regulations (EU) No 168/2013 and (EU) 2019/1020 and Directive (EU) 2020/1828 (Cyber Resilience Act). https://eur-lex.europa.eu/eli/reg/2024/2847/oj. Official Journal of the European Union, 20 November 2024. [9] Executive Office of the President. 2021. Executive Order 14028: Improving the Nation’s Cybersecurity. https://www.federalregister.gov/documents/2021/05/ 17/2021-10460/improving-the-nations-cybersecurity. Federal Register, 86 FR 26633, Document No. 2021-10460. [10] Andreas Halbritter and Dominik Merli. 2024. Accuracy Evaluation of SBOM Tools for Web Applications and System-Level Software (ARES ’24). Association for Computing Machinery, New York, NY, USA, Article 55, 9 pages. doi:10.1145/ 3664476.3670926 [11] Rio Kishimoto, Tetsuya Kanda, Yuki Manabe, Katsuro Inoue, Shi Qiu, and Yoshiki Higo. 2025. A Dataset of Software Bill of Materials for Evaluating SBOM Consumption Tools. arXiv:2504.06880 [cs.SE] https://arxiv.org/abs/2504.06880 [12] Linux Foundation. 2010. SPDX Specification. https://spdx.dev. [13] Mehdi Mirakhorli, Derek Garcia, Schuyler Dillon, Kevin Laporte, Matthew Morrison, Henry Lu, Viktoria Koscinski, and Christopher Enoch. 2024. A Landscape Study of Open Source and Proprietary Tools for Software Bill of Materials (SBOM). arXiv:2402.11151 [cs.SE] https://arxiv.org/abs/2402.11151 [14] US NTIA. 2021. The Minimum Elements for a Software Bill of Materials (SBOM). https://www. ntia. doc. gov/files/ntia/publications/sbom_minimum_elements_report. pdf (2021). [15] Eric O’Donoghue, Yvette Hastings, Ernesto Ortiz, and A. Redempta Manzi Muneza. 2025. Software Bill of Materials in Software Supply Chain Security A Systematic Literature Review. arXiv:2506.03507 [cs.SE] https://arxiv.org/abs/ 2506.03507 [16] Marc Ohm, Henrik Plate, Arnold Sykosch, and Michael Meier. 2020. Backstabber’s Knife Collection: A Review of Open Source Software Supply Chain Attacks. International Journal of Information Security 19, 6 (2020), 709–722. https://www. semanticscholar.org/paper/Backstabber%E2%80%99s-Knife-Collection%3A-AReview-of-Open-Ohm-Plate/4c7183fb2109271405e4a0fe23b5e827520a9f68 [17] OWASP. 2020. CDXGen: CycloneDX Generator. https://github.com/CycloneDX/ cdxgen. [18] OWASP Foundation. 2018. CycloneDX Specification. https://cyclonedx.org. [19] OWASP Foundation. 2026. CycloneDX Tool Center. https://cyclonedx.org/toolcenter/. Accessed: 2026-06-19. References 288 SBOM-related tools as of June 2026. 11