Scanning a bill of materials (--sbom)
--sbom scans the components named in a CycloneDX JSON document — the standard
hand-off between a build system and a scanner, and the one input every other
scanner accepts. It is for the case where the SBOM is what you have: a build
published one, a vendor sent one, a policy requires one.
vexscan --sbom sbom.cdx.json --all
syft debian:12 -o cyclonedx-json | vexscan --sbom - --all
vexscan --sbom sbom.cdx.json --all --ecosystem golang
vexscan --sbom sbom.cdx.json --format inventory
- reads standard input. The flag is mutually exclusive with --image,
--rootfs, --repo and --rpm, and the report says "mode": "sbom".
Components are routed to the plugin that can query them, from the purl type:
pkg:golang → Go, pkg:npm → npm, pkg:pypi → PyPI, pkg:maven → Maven, and
pkg:deb / pkg:rpm / pkg:apk → the OS plugin. --ecosystem and the
per-ecosystem outcome list behave exactly as they do for an image.
Read this part before trusting a result
Every finding is undetermined. Not some — every one. --rpm has no
filesystem either, but an rpm header still lists the files the package installs
and file(1)'s verdict on each, which is enough to rule out a package that
ships no executable code. A CycloneDX component carries a name, a version and a
purl. There is nothing in it to rule anything out with, so nothing is ruled out:
NOTE: this read a bill of materials, not an installed system. No ELF
reachability test could run -- there is no filesystem to trace -- and a
CycloneDX component does not list the files it installs, so unlike a
package file it cannot rule a package out for shipping no code either.
Every row below is a package the document says is installed, and
nothing here can say whether its code would ever run.
89 finding(s) below are undetermined for that reason. Scan the image
or tree these components came from to get an answer.
That note prints at both ends of the report, and it prints on a clean one too: "no findings" out of a bill of materials is a much weaker statement than the same words out of an image, and the difference has to be on the page.
So this mode answers which advisories apply to what this document says is
installed — the same question a version-matching scanner answers, and nothing
more. Point vexscan at the image or the tree when you want the answer only it
can give.
The source name is why this finds anything
Debian, Alpine and the RPM distributions all file advisories against the
source package, and the binary package in the document is usually named
something else. Both producers say so, in different places: syft writes
upstream=openssl as a purl qualifier, trivy writes an
aquasecurity:trivy:SrcName property. vexscan reads both and queries the
binary and source names together. Missing it queries a name OSV has no records
under, which reads exactly like a clean package.
The distribution comes from the distro= qualifier — distro=debian-12,
and Alpine's bare distro=3.19.9 resolved through the purl namespace. A
document that states no distribution, or states two, is an error naming
--osv-ecosystem, on the same reasoning as --rpm: an OSV query with no
ecosystem finds nothing and reads like a clean scan.
Nothing is dropped quietly
A document with 400 components of which 120 were unusable must not print as a scan of 280. Two things can be wrong with an entry, and they are not the same:
- Skipped — it named no package to begin with. The
operating-systemrow, trivy'sgo.modmarker, a purl typevexscanhas no ecosystem for, or a component with no version to match a range against. Each is logged with its reason. These are ordinary, and not a loss. - Failed — it had a package URL and the URL would not parse. That is a
component that went unexamined, so it lands in
unreadablealongside a directory that could not be read, is named with its reason, and the scan exits 1.
A document nobody could read at all is an error, never an empty result — and so is one where every entry resolved and none of them was a package this tool can query. Scanning clean is the one outcome an empty result may never produce.
Only CycloneDX JSON is read today. An SPDX document is told what it is rather than scanned as a document with no components in it.