Trivy can generate Software Bill of Materials (SBOMs) in both CycloneDX and SPDX formats, but its primary strength lies in how it discovers the software in the first place, not just how it formats the output.
Let’s see Trivy in action generating a CycloneDX SBOM for a simple Docker image. Imagine we have a container image, say nginx:latest.
First, we need to install Trivy if you haven’t already. On macOS, it’s brew install aquasecurity/trivy/trivy. On Linux, you can download the binary from the GitHub releases page.
Now, let’s scan the nginx:latest image and output a CycloneDX SBOM. We’ll use the --format cyclonedx flag and specify the output file with --output sbom-cyclonedx.json.
trivy image --format cyclonedx --output sbom-cyclonedx.json nginx:latest
After running this, you’ll have a sbom-cyclonedx.json file. Let’s peek inside. You’ll see a JSON structure conforming to the CycloneDX schema. It will list components, their versions, licenses, and crucially, their relationships. For nginx:latest, you might see entries for the nginx package itself, potentially underlying OS packages like libc6, and any other dependencies Trivy could identify.
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"version": 1,
"metadata": {
"timestamp": "2023-10-27T10:30:00Z",
"tools": [
{
"vendor": "Aqua Security",
"name": "Trivy",
"version": "0.45.0"
}
],
"component": {
"type": "application",
"name": "nginx:latest",
"bom-ref": "pkg:docker/nginx@latest?tag=latest"
}
},
"components": [
{
"type": "operating-system",
"name": "Debian GNU/Linux",
"version": "11",
"bom-ref": "pkg:deb/debian/base-files@11?os_name=debian"
},
{
"type": "library",
"name": "nginx",
"version": "1.25.3",
"licenses": [
{
"id": "20"
}
],
"bom-ref": "pkg:rpm/centos/nginx@1.25.3?arch=x86_64&distro=centos-stream-8"
}
// ... more components
]
// ... dependencies, services, etc.
}
Generating an SPDX SBOM is nearly identical. Just swap the format flag:
trivy image --format spdx --output sbom-spdx.json nginx:latest
This will produce sbom-spdx.json, which follows the SPDX specification, using document creation information, package information, and relationships between them.
The real magic of Trivy’s SBOM generation isn’t the format itself; it’s Trivy’s discovery engine. It can analyze container images, Kubernetes clusters, Git repositories, and filesystem directories. For container images, it doesn’t just look at the installed packages from the OS package manager. It can also identify application dependencies installed via package managers like npm, pip, Maven, NuGet, and more. This broad reach means Trivy can build a more comprehensive picture of your software supply chain than many other tools.
The key levers you control are:
- Target: What you’re scanning (image, repo, directory).
- Format: CycloneDX or SPDX.
- Output: Where the SBOM is saved.
- Filter: You can filter by vulnerability severity (
--severity), file path (--skip-files), and more, which implicitly affects the SBOM content by excluding certain findings.
The most surprising thing is how Trivy reconstructs the filesystem and package manager databases to infer dependencies that aren’t explicitly declared in a single manifest file. For instance, in a Python application, it can often detect libraries installed via pip install -r requirements.txt even if the requirements.txt file itself isn’t present in the final image layer, by analyzing the installed package metadata. This deep analysis allows it to build a more accurate dependency graph.
The next step after generating an SBOM is often to analyze it for vulnerabilities or to ensure license compliance.