A Software Bill of Materials (SBOM) is a complete inventory of every component in your software -- libraries, frameworks, tools, and their versions. On its own, an SBOM is a list. Combined with vulnerability scanning, it becomes one of the most powerful tools for managing security risk in your software supply chain.
This guide covers how to generate an SBOM, which format to use, and how to set up continuous SBOM vulnerability scanning in your development workflow.
An SBOM answers a simple question: what is inside this software? It lists every component, its version, its supplier, and its relationship to other components. Think of it as a package-lock.json or composer.lock, but standardized, comprehensive, and machine-readable across ecosystems.
SBOMs became a regulatory requirement for US federal software suppliers after Executive Order 14028 in 2021. Since then, adoption has grown rapidly across the private sector. The EU Cyber Resilience Act, taking effect in 2027, will require SBOMs for all products with digital elements sold in Europe.
But the practical value goes beyond compliance. An SBOM gives you:
Two formats dominate the SBOM landscape:
Developed by OWASP, CycloneDX is designed specifically for security use cases. It supports JSON and XML, is lightweight, and has strong tooling support. It is the preferred format for vulnerability scanning workflows.
SPDX (Software Package Data Exchange) is an ISO standard (ISO/IEC 5962:2021) maintained by the Linux Foundation. It has broader scope, covering licensing and provenance in addition to component inventory. SPDX supports JSON, XML, YAML, RDF, and tag-value formats.
For vulnerability scanning purposes, either format works. CycloneDX tends to be simpler to generate and parse. SPDX is more common in compliance-heavy environments. Choose based on your toolchain and downstream consumers.
Several tools can generate SBOMs from your project. Here are the most practical options for each ecosystem:
Syft by Anchore is one of the most versatile SBOM generators. It supports container images, file systems, and most package ecosystems:
# Install Syft
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s
# Generate CycloneDX SBOM from a directory
syft dir:. -o cyclonedx-json > sbom.cdx.json
# Generate SBOM from a container image
syft alpine:3.19 -o cyclonedx-json > alpine-sbom.cdx.json
# Generate SPDX format
syft dir:. -o spdx-json > sbom.spdx.json
cdxgen is purpose-built for CycloneDX and has excellent language-specific support:
# Install cdxgen
npm install -g @cyclonedx/cdxgen
# Generate SBOM for a Node.js project
cdxgen -o sbom.json
# Generate SBOM for a PHP/Composer project
cdxgen -t php -o sbom.json
# Generate SBOM for a Python project
cdxgen -t python -o sbom.json
# PHP/Composer: CycloneDX plugin
composer require --dev cyclonedx/cyclonedx-php-composer
composer make-bom --output-file=sbom.xml
# Python: CycloneDX module
pip install cyclonedx-bom
cyclonedx-py requirements -i requirements.txt -o sbom.json --format json
# Node.js: CycloneDX module
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
Once you have an SBOM, you need to match its components against vulnerability databases. This is where the real value emerges.
Grype (also by Anchore) scans SBOMs against the NVD, GitHub Security Advisories, and other sources:
# Install Grype
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s
# Scan an SBOM
grype sbom:sbom.cdx.json
# Output in JSON for automation
grype sbom:sbom.cdx.json -o json > vulnerabilities.json
# Filter by severity
grype sbom:sbom.cdx.json --fail-on high
Sample output:
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
express 4.18.2 4.19.3 npm CVE-2026-1234 High
lodash 4.17.20 4.17.21 npm CVE-2025-5678 Medium
node 20.11.0 20.11.1 binary CVE-2026-9012 Critical
Google's OSV-Scanner works with both SBOMs and lockfiles directly:
# Scan an SBOM
osv-scanner --sbom=sbom.cdx.json
# Or scan lockfiles directly
osv-scanner --lockfile=package-lock.json
osv-scanner --lockfile=composer.lock
The most effective setup generates a fresh SBOM on every build and scans it automatically:
# GitHub Actions workflow
name: SBOM Security Scan
on: [push, pull_request]
jobs:
sbom-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Generate SBOM
run: |
npx @cyclonedx/cyclonedx-npm --output-file sbom.cdx.json
- name: Scan for vulnerabilities
uses: anchore/scan-action@v4
with:
sbom: sbom.cdx.json
fail-build: true
severity-cutoff: high
- name: Upload SBOM as artifact
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.cdx.json
Store SBOMs as build artifacts. When a new CVE is published, you can scan historical SBOMs to determine which deployments are affected without rebuilding anything.
CI/CD scanning catches vulnerabilities known at build time. But new CVEs are published daily. To close the gap between CI runs, feed your SBOM into a continuous monitoring service that watches for new disclosures and alerts you in real time.
The workflow looks like this:
This approach gives you the best of both worlds: gate your builds on known vulnerabilities, and get alerted to new ones between builds.
If you have never generated an SBOM, start simple: install Syft, run it against your project, and scan the output with Grype. You will likely find a few known vulnerabilities on your first run. Address the critical ones, integrate the scan into your CI pipeline, and set up continuous monitoring for everything else. The entire setup takes less than an hour, and the ongoing maintenance is minimal once automated.
SBOM vulnerability scanning is quickly becoming a baseline expectation for professional software teams. Starting now puts you ahead of the curve before it becomes a hard requirement.
Get instant alerts when new CVEs affect your technologies. Free to start, no credit card required.
Get Started Free →