How osv-scanner Processes CycloneDX SBOM Files for Security Analysis
OSV-Scanner ingests CycloneDX SBOM files as standardized package manifests, extracts component metadata using the Scalibr framework, and maps discovered vulnerabilities back to specific SBOM coordinates while optionally emitting vulnerability-enriched CycloneDX reports.
The google/osv-scanner tool treats CycloneDX SBOM files as first-class inputs for vulnerability detection. When you provide a CycloneDX file—typically with a .cdx.json extension—the scanner parses its component inventory and queries the Open Source Vulnerabilities (OSV) database for matching security issues. This integration enables security teams to audit software bill of materials without requiring access to original package manager files.
SBOM Detection and Extractor Resolution
Plugin Resolution for SBOM Processing
When you invoke osv-scanner with the --sbom flag, the scan command adds the specified path to actions.SBOMPaths. In pkg/osvscanner/scan.go, the scanner initializes extractors by calling scalibrplugin.Resolve([]string{"sbom"}, ...), which loads the default SBOM preset defined in internal/scalibrplugin/presets.go. This preset includes the CycloneDX extractor (github.com/google/osv-scanner/extractor/filesystem/sbom/cdx) alongside other SBOM format handlers.
File Matching and Extractor Selection
For each SBOM path provided, the scanner evaluates whether the CycloneDX extractor should handle the file by calling its FileRequired method. If the filename matches CycloneDX patterns, the extractor is stored in an overrideMap that associates specific file paths with their dedicated parsers. This mapping ensures that when scalibr.New().Scan executes, it routes the file to the correct CycloneDX parser rather than using generic file detection.
// Adding a CycloneDX SBOM path from user input
actions.SBOMPaths = []string{"/tmp/project/deps.cdx.json"}
// Scan logic: selecting the CycloneDX extractor
sbomExtractors := scalibrplugin.Resolve([]string{"sbom"}, []string{}, &cpb.PluginConfig{})
for _, se := range sbomExtractors {
sbomExtractor := se.(filesystem.Extractor)
if sbomExtractor.FileRequired(simplefileapi.New(absPath, nil)) {
// CycloneDX extractor matches the file name pattern
overrideMap[absPath] = sbomExtractor
break
}
}
Parsing CycloneDX Components
Extracting Package Metadata
During the actual scan execution, the Scalibr framework invokes the selected CycloneDX extractor to parse the JSON structure. The extractor reads the CycloneDX document and builds a slice of extractor.Package objects representing each component defined in the SBOM. For each package, it attaches cdxmeta.Metadata containing the original component coordinates from the CycloneDX document.
Location Tracking with CDXMetadata
The metadata includes CDXLocations, which preserves the specific component identifiers and nested positions within the SBOM hierarchy. This provenance data ensures that vulnerability results can reference exact paths within the original document, such as specific component IDs or nested dependency relationships.
Annotating Vulnerability Sources
After extraction, pkg/osvscanner/vulnerability_result.go processes each package to determine its origin. If a package's plugin list contains cdx.Name, indicating it originated from CycloneDX parsing, the scanner appends the first CDX location to the source path. This creates a compound source string that provides precise traceability from vulnerability findings to specific SBOM entries.
// Annotating the source path with CDX location data
if slices.Contains(p.Plugins, cdx.Name) {
// p.Metadata is *cdxmeta.Metadata
locations := p.Metadata.(*cdxmeta.Metadata).CDXLocations
if len(locations) > 0 {
source.Path = source.Path + ":" + locations[0] // e.g., sbom:/path/file.cdx.json:pkg:my-lib
}
}
Generating CycloneDX Output Reports
Version-Specific BOM Creation
OSV-Scanner can emit its findings as CycloneDX-formatted SBOMs that include vulnerability data. The internal/output/cyclonedx.go file handles this by selecting a specific CycloneDX version—models.CycloneDXVersion14, models.CycloneDXVersion15, or models.CycloneDXVersion16—defined in pkg/models/cyclonedx.go. It then invokes the appropriate BOM creator from internal/output/sbom/models.go, such as ToCycloneDX14Bom, ToCycloneDX15Bom, or ToCycloneDX16Bom.
Vulnerability Aggregation by PURL
The builders in internal/output/sbom/cyclonedx_common.go group packages by their Package URL (PURL) and inject vulnerability details into the BOM's metadata. This produces a standards-compliant CycloneDX document that describes not only the components but also their associated security vulnerabilities, encoded as JSON and written to the specified output writer.
// Emit a CycloneDX BOM with discovered vulnerabilities
err := output.PrintCycloneDXResults(vulnResult, models.CycloneDXVersion15, os.Stdout)
Summary
- Detection: Scanning CycloneDX files requires the
--sbomflag, which triggers extractor resolution inpkg/osvscanner/scan.gousing Scalibr's plugin system. - Parsing: The CycloneDX extractor validates files via
FileRequiredand parses components intoextractor.Packageobjects withCDXMetadatacontaining precise location data. - Traceability: Vulnerability results preserve SBOM provenance by appending CDX locations to source paths, creating traceable identifiers like
sbom:/path/file.cdx.json:component-id. - Output: The scanner supports generating CycloneDX 1.4, 1.5, and 1.6 output documents that aggregate vulnerabilities by PURL using version-specific builders in
internal/output/sbom/.
Frequently Asked Questions
What file patterns does osv-scanner recognize for CycloneDX SBOMs?
The CycloneDX extractor identifies files based on CycloneDX-specific filename conventions, typically matching .cdx.json extensions or similar patterns. When processing the --sbom input paths, the extractor's FileRequired method validates whether the target file matches these known CycloneDX signatures before attempting to parse the JSON structure.
How does osv-scanner map vulnerabilities back to SBOM components?
After parsing, packages originating from CycloneDX sources contain metadata with CDXLocations arrays. In pkg/osvscanner/vulnerability_result.go, the scanner checks for the cdx.Name plugin identifier and appends the first location entry to the source path, creating a composite string that points to the specific component within the original SBOM file.
Can osv-scanner output CycloneDX format with vulnerability data?
Yes. The scanner can generate CycloneDX-formatted SBOMs that include vulnerability information using the appropriate output configuration. This invokes builders in internal/output/sbom/models.go to create version-specific BOMs (1.4, 1.5, or 1.6) that group packages by PURL and embed vulnerability details according to the CycloneDX specification.
Which CycloneDX specification versions are supported?
OSV-Scanner supports CycloneDX versions 1.4, 1.5, and 1.6. The desired version is specified via configuration flags, and the corresponding creator function—such as ToCycloneDX15Bom—is selected from the sbom.SpecVersionToBomCreator map to ensure the output conforms to the chosen specification.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →