With Trivy, how do you generate an SBOM for a container image and later re-check it against new advisories without pulling the image?
answer
- write an inventory once, match it often
- an output format on a normal scan
- cyclonedx, spdx or spdx-json
- a subcommand that takes a file path
- today's database, last year's packages
basics
~20 sRun trivy image with --format cyclonedx, spdx or spdx-json and --output to save the package inventory with the release. Later, trivy sbom on that file matches the recorded packages against Trivy's current vulnerability database, with no image pull.
solid answer
~40 sGenerating an SBOM is just an output format: `trivy image --format cyclonedx --output app-1.4.0.cdx.json registry.example.internal/shop/app:1.4.0` writes a CycloneDX JSON inventory (`spdx` gives SPDX tag-value, `spdx-json` SPDX JSON; CycloneDX XML is not supported). I keep that file next to the release. Months later, `trivy sbom app-1.4.0.cdx.json` detects the format and runs the vulnerability scanner, which is the default for `trivy sbom`, matching the recorded packages against the database Trivy has today. CVEs published since the release show up without pulling or rebuilding anything. The limit is the inventory itself: the SBOM holds package records, not files, so secrets and misconfigurations are out of reach, and a package the SBOM never recorded is never checked.
code
bash · 3 linestrivy image --format cyclonedx --output app-1.4.0.cdx.json registry.example.internal/shop/app:1.4.0
trivy sbom --severity HIGH,CRITICAL app-1.4.0.cdx.json
trivy sbom --scanners vuln,license app-1.4.0.cdx.jsongo deeper
Recall the two steps: an SBOM value on --format with --output at release time, then trivy sbom on the saved file. Be able to name cyclonedx, spdx and spdx-json.
Explain that trivy sbom matches the recorded packages against the current database, which is why new CVEs appear, and that it runs only the vuln and license scanners.
Show where the re-check stops: nothing outside the inventory is seen, third-party SBOMs can match less well, and a deleted image cannot be rescanned for secrets.
Treat stored SBOMs as the fast, cheap answer to which past releases are exposed, and weigh that against the cost of retaining images for questions an inventory cannot answer.
## What an SBOM is, in Trivy's terms A **software bill of materials (SBOM)** is a machine-readable inventory of the components inside an artifact: each package's name, version, a package URL (**purl**) that identifies its ecosystem, and usually its declared license. Trivy does not have a separate "generate" command. SBOM output is a value of `--format` on its ordinary scanning subcommands such as `image`, `fs`, `rootfs` and `vm`, written to a file with `--output`. | `--format` value | What Trivy writes | Note | |---|---|---| | `cyclonedx` | CycloneDX JSON | CycloneDX XML is not supported | | `spdx` | SPDX tag-value text | the line-oriented SPDX form | | `spdx-json` | SPDX JSON | the JSON serialisation of SPDX | When one of these formats is chosen and `--scanners` is not set, Trivy logs that the format "disables security scanning" and produces only the inventory. A Trivy-written CycloneDX file for an image carries the components, an `operating-system` component for the base distribution, and Trivy's own properties such as `aquasecurity:trivy:SrcName` and `aquasecurity:trivy:LayerDiffID`. ## Re-checking with `trivy sbom` `trivy sbom <path>` takes an SBOM as the scan target. The format is detected automatically, and the accepted inputs are: - CycloneDX JSON, SPDX tag-value and SPDX JSON documents; - a CycloneDX-type in-toto attestation, such as the `.cdx.intoto.jsonl` that `cosign verify-attestation --type cyclonedx` prints, and SPDX attestations since Trivy 0.68.0; - a **KBOM**, the cluster inventory written by `trivy k8s --format cyclonedx`. On this subcommand `--scanners` accepts only `vuln` and `license`, and the default is `vuln`. Trivy rebuilds the package list from the document and matches it against the vulnerability database it has now. How that database is fetched, mirrored or kept fresh is a separate subject. What matters here is that the advisories are today's and the packages are the ones recorded at release time. ## Why this is the cheap way to re-check old releases 1. **No image pull.** Nothing is downloaded from the registry and no layer is unpacked, so checking a hundred past releases takes minutes, not hours. 2. **The image may be gone.** Registry retention rules delete old tags. The SBOM survives as long as you keep it. 3. **No rebuild.** Rebuilding last year's release today would pull today's base image and dependencies, so you would be scanning a different artifact from the one you shipped. 4. **Stable input.** The same file scanned on two dates differs only by what the advisories say, which is exactly the signal you want. ## Where the re-check stops - **Only recorded packages.** If the SBOM never listed a component, no advisory can match it. - **No file contents.** Secret and misconfiguration scanning need files; `trivy sbom` accepts neither scanner. License findings come from the license fields recorded in the document, and `--license-full`, which reads license files, is not offered on `trivy sbom`. - **Producer matters.** The Trivy documentation warns that SBOMs written by other tools may detect less accurately, because Trivy relies on its own properties in the document. - **Format support.** A CycloneDX XML document cannot be read. ## A worked example Release 1.4.0 of a service shipped in March with a CycloneDX SBOM written by `trivy image`. In October an advisory lands for a TLS library. The question from the incident channel is which of the last forty releases contain the affected version. - Pulling forty images, some already deleted by retention, would be slow and partly impossible. - Rebuilding them would scan today's dependencies, not the ones that shipped. - Looping `trivy sbom --severity HIGH,CRITICAL` over the forty stored files answers it in minutes, because each run matches the recorded package versions against the advisory Trivy now knows about. The answer is only as good as each file. A release whose SBOM never recorded the library, for example because it was compiled from source and copied into the image by hand, will look clean. That is a limit of the inventory, not of the re-check. ## Common mistakes - Treating a CycloneDX file that already embeds vulnerabilities as the current answer. Those entries are a snapshot from the day it was written. - Expecting `trivy convert` to refresh anything. It re-renders a Trivy JSON report and never consults the database. - Writing SBOMs with an SBOM format and assuming the same run also checked for vulnerabilities. Without an explicit `--scanners`, it did not. ## A routine that works 1. At release, write the SBOM with an SBOM format and store it keyed by the image digest. 2. On a schedule, loop `trivy sbom` over the stored files and collect the findings. 3. When a stored file needs refreshing in place, `trivy sbom --scanners vuln --format cyclonedx` writes the original BOM back with an updated vulnerabilities section (Trivy 0.67.0 and later). 4. Keep the image itself where you also need secret or layer-level answers. ## Version notes This answer is written for Trivy 0.74.0. SPDX attestation input arrived in 0.68.0, and in-place CycloneDX refresh in 0.67.0.
- Which input formats does `trivy sbom` accept?CycloneDX JSON, SPDX tag-value and SPDX JSON; a CycloneDX-type in-toto attestation such as the output of `cosign verify-attestation --type cyclonedx`; SPDX attestations since 0.68.0; and a KBOM written by `trivy k8s --format cyclonedx`. The format is detected automatically. CycloneDX XML is not supported.
- Can `trivy sbom` tell you whether last year's image shipped a leaked credential?No. `trivy sbom` accepts only the `vuln` and `license` scanners, and the SBOM holds package records rather than file contents. Secret detection needs the image itself through `trivy image`, so if the image has been deleted the SBOM cannot answer that question.
- How do you get a refreshed CycloneDX file instead of a table?Run `trivy sbom --scanners vuln --format cyclonedx --output app-1.4.0.refreshed.cdx.json app-1.4.0.cdx.json`. Since 0.67.0 Trivy keeps the original BOM's components and relationships and rewrites only the vulnerabilities. The explicit `--scanners vuln` matters, because an SBOM output format with no `--scanners` setting turns scanning off.
A stored SBOM is a shipment's packing list filed at dispatch: when a recall notice comes out you check the list instead of unpacking every crate, and anything never written on the list cannot be found from it.
saying these in an interview costs you the question
- Re-checking an old release means rebuilding it from source first.
- trivy sbom just replays the vulnerabilities recorded when the SBOM was written.
- Trivy writes CycloneDX XML if you ask for it.
- A stored SBOM lets you re-check secrets and misconfigurations too.
- trivy convert re-checks a stored SBOM against new advisories.