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 --sbom flag, which triggers extractor resolution in pkg/osvscanner/scan.go using Scalibr's plugin system.
  • Parsing: The CycloneDX extractor validates files via FileRequired and parses components into extractor.Package objects with CDXMetadata containing 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →