Quality, completeness and depth
An incomplete SBOM is worse than no SBOM: it gives false assurance. This page defines what a usable SBOM is and how to verify it automatically.
Quality criteria
| Criterion | Question | Verifiable |
|---|---|---|
| Completeness | Are all components present? | By gap with the analysed SBOM |
| Accuracy | Do the versions match the actual artefact? | By hash |
| Freshness | Does the SBOM correspond to the latest build? | By timestamp and build reference |
| Resolvable identifiers | Does every component carry a valid purl or cpe? |
Automatic |
| Licences populated | What proportion of NOASSERTION? |
Automatic |
| Relationships expressed | Is the dependency graph present? | Automatic |
| No unknowns | How many components have no name, no version, or are unidentified? | Automatic |
| Declared completeness | Does the composition section honestly state coverage? | Automatic |
Automated scoring
Every SBOM produced receives a score against these criteria, and the threshold is blocking in CI. The policy must state explicitly:
- the minimum score for a build to be promotable to production;
- the maximum tolerated proportion of components without a resolvable identifier;
- the maximum proportion of
NOASSERTIONlicences; - the maximum tolerated gap between build SBOM and analysed SBOM.
Without a numeric threshold, “SBOM quality” remains an intention. With a blocking threshold it becomes a property of the pipeline.
Depth: direct and transitive
The Regulation requires at the very least top-level dependencies. That floor is insufficient in practice.
| Direct dependencies | Transitive dependencies | |
|---|---|---|
| Definition | Explicitly declared by you | Dragged in by your dependencies |
| Typical volume | Dozens | Hundreds to thousands |
| Control | You choose them | You inherit them |
| Share of supply chain incidents | Minority | Majority |
The doctrine adopted: full depth, with an explicit direct / transitive distinction in the graph, to support prioritisation and to identify how a problematic component got in.
Which dependencies to include
| Category | In the shipped product’s SBOM? |
|---|---|
| Runtime dependencies | Yes, no discussion |
| Build dependencies whose output is embedded | Yes |
| Build dependencies not embedded | In a separate build-chain SBOM |
| Test dependencies | No in the product SBOM — their presence is a major cause of false positives |
| Container base image packages | Yes if shipped with the product |
The seven traps
1. Statically linked binaries. A C or Rust library compiled into the executable appears in no manifest. Remedy: binary analysis, and language-specific tools.
2. Vendored code. Third-party sources copied into your repository, often modified. Remedy: file-hash detection, of the kind licence-oriented composition analysis tools perform.
3. Container system dependencies. The base image brings in dozens of packages. Remedy: generate the SBOM on the image, not only on the application; shrink the surface with minimal images.
4. Multi-language artefacts. A Python package embedding a compiled native library, a Node module with a binary. Remedy: combine several generators.
5. Code generated at build time. The generator itself has dependencies, and the code it produces may embed some. Remedy: document the generation chain in the SBOM.
6. Firmware. Embedded file systems, partitions, binary blobs. Remedy: firmware analysis tooling, and a contractual SBOM requirement on the platform supplier.
7. Renamed or repackaged components. The same component under two names in two ecosystems.
Remedy: normalisation by purl — see Identifiers.
What to write down
A one-page SBOM quality policy setting: format and version, required depth, dependency categories included, minimum score, blocking thresholds, the temporary waiver procedure and its automatic expiry.