Trivy 0.74's `trivy sbom` reports no OS-package vulnerabilities for a stored CycloneDX SBOM of a Debian-based image — what in the file do you check?
answer
- only as good as the file
- which distribution's advisories apply
- a component of a particular type
- identifiers Trivy can decode
- --debug shows what was skipped
basics
~20 sCheck for an operating-system component naming the distribution and its version, and for a purl on every package component. Without the first, Trivy has no distribution advisories to match; components lacking a usable purl are skipped. Neither stops the scan.
solid answer
~40 sTrivy rebuilds its scan target from the SBOM, so I check what it needs from the file. First, a component of `type` `operating-system` with the family as its name and the release as its version, for example `debian` and `12.5`: that is how Trivy picks the distribution's advisories, and without it the OS packages produce no findings. Second, every package component needs a purl Trivy can classify, such as `pkg:deb/debian/...`; components without one, or with an unsupported purl type, are skipped with only a debug log line. Third, the producer: the Trivy docs warn that SBOMs from other tools can detect less accurately because Trivy relies on its own properties, such as `aquasecurity:trivy:SrcName`. I rerun with `--debug` to see what was skipped.
code
json · 19 lines{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"components": [
{
"bom-ref": "3c0e5f8a-1b2d-4e6f-9a7b-5d4c3b2a1f00",
"type": "operating-system",
"name": "debian",
"version": "12.5"
},
{
"bom-ref": "pkg:deb/debian/[email protected]~deb12u2?distro=debian-12.5",
"type": "library",
"name": "libssl3",
"version": "3.0.11-1~deb12u2",
"purl": "pkg:deb/debian/[email protected]~deb12u2?distro=debian-12.5"
}
]
}go deeper
Remember that trivy sbom only knows what the file says: it needs to know the operating system and needs an identifier on each package.
Explain the decoding: the operating-system component sets the family and release, purls define packages, and anything missing them is skipped without an error.
Show the diagnosis: --debug for skipped components, the Detected OS line, purl counts, and a comparison against a fresh SBOM when the image still exists.
Argue for validating SBOMs at write time, because an archived inventory with gaps becomes a permanent blind spot once the image is deleted.
## How `trivy sbom` builds its target When Trivy scans an SBOM it does not look at an image at all. It decodes the document into the same internal structure an image scan would produce, then runs detection on that. In Trivy 0.74.0 the decoder works like this for CycloneDX: - The **root component**'s Trivy properties (image ID, repo digest, diff IDs, tags) become scan metadata when present. - A component of type `operating-system` sets the **OS family and release**: its `name` is the family and its `version` the release. Only the first one counts. A second triggers the warning `Multiple OS components are not supported, taking the first one and ignoring the rest`. - A component of type `library`, or any other component that carries a **purl**, is decoded as a package, provided the purl is one Trivy can classify. Its ecosystem, name and version come from the purl. - A component **without a purl** is skipped, logged at debug level as `Skipping a component without PURL`. A purl of a type Trivy does not classify is skipped the same way. OS packages are matched against advisories for the OS family and release. If no OS was decoded, Trivy has nothing to choose those advisories by. The OS-package part of the scan returns no findings, and the run still completes normally. ## The checklist | What to check | Why Trivy needs it | Symptom when it is missing | |---|---|---| | An `operating-system` component with name and version | selects the distribution's advisories | no OS-package findings, no error | | A purl on every package component | gives ecosystem, name and version | the component is silently skipped | | Exactly one OS component | only the first is used | a warning; a wrong first entry mismatches advisories | | Trivy's own properties, e.g. `aquasecurity:trivy:SrcName` | improve matching | the docs warn of less accurate detection for other tools' SBOMs | | JSON CycloneDX or SPDX | the formats Trivy can parse | CycloneDX XML cannot be read | ## Diagnosing it 1. Rerun with `--debug` and look for `Skipping a component` lines. At normal verbosity they are invisible. 2. Look for the INFO line `Detected OS`. An image-built SBOM scanned correctly prints it; its absence means no OS was decoded. 3. Count components without a purl; the `operating-system` component has none by design, so expect at least that one. A few lines of `jq` will do: ```bash jq '[.components[] | select(.purl == null)] | length' app-1.4.0.cdx.json jq '[.components[] | select(.type == "operating-system")]' app-1.4.0.cdx.json ``` 4. If the image still exists, write Trivy's own SBOM from it and compare the component counts. A large gap tells you the stored file is incomplete. Why two producers disagree is a separate subject. ## A worked example Two SBOMs describe the same Debian-based image. One was written by `trivy image --format cyclonedx`; the other came from a different generator in a vendor's release bundle. - Scanned with `trivy sbom`, the first prints `Detected OS` with family `debian` and lists findings for OS packages and application libraries. - The second prints no `Detected OS` line and reports only a handful of application-library findings. - Opening the second file shows the deb packages with purls but no component of type `operating-system`. The image's base distribution was recorded only as a free-text property that Trivy does not read. The packages were there, but Trivy had no distribution and release to match them against, so the OS-package scan produced nothing. The fix belongs at the source: configure the generator to emit the operating-system component, or write the archived SBOM with Trivy in the first place. ## Why this matters for old releases A stored SBOM is often the **only evidence** left for a release whose image has been deleted. A gap in it is permanent: a component the file never identified can never be matched against an advisory, however many times you re-check it. So validate SBOMs **when you write them**: - run `trivy sbom` on the new file in the same pipeline and confirm the `Detected OS` line and a non-zero package count; - reject a file with no OS component when the artifact is a distribution-based image; - keep the generator's configuration under review, rather than repairing files afterwards. Hand-editing an OS component into an archived file changes the record of what you shipped. If you must, work on a labelled copy and keep the original. ## Zero is not clean A `trivy sbom` run that reports nothing proves only that nothing **in the decoded package list** matched. Before reading a zero as good news, check that the decoder actually saw the operating system and the packages.
- The SBOM has two operating-system components. What does Trivy do?It uses the first, ignores the rest and logs `Multiple OS components are not supported, taking the first one and ignoring the rest` as a warning. If the first entry is the wrong distribution, OS packages are matched against the wrong advisories, so the order in the file matters.
- Should you hand-edit an operating-system component into an archived SBOM to make the scan work?Only on a labelled copy. The archived file is the record of what shipped, and editing it in place destroys that record. Keep the original, note why the copy differs, and fix the generator so future SBOMs carry the component.
saying these in an interview costs you the question
- If trivy sbom exits cleanly, every component in the file was scanned.
- Trivy works out the distribution from the package names when no OS component exists.
- Any valid CycloneDX document scans equally well whichever tool wrote it.
- Components without a purl are matched by name and version instead.
- Zero findings from a stored SBOM proves the release is clean.