Diff two CycloneDX or SPDX SBOMs and produce human-readable change reports. Highlights added, removed, upgraded dependencies and new CVEs.
Compare two CycloneDX or SPDX SBOM files and instantly see what changed: added packages, removed packages, version upgrades, license changes (e.g. a dependency that switched from MIT to GPL-3.0), and newly introduced CVEs. Output as human-readable text, JSON, or Markdown — perfect for CI/CD gates and audit trails.
npm install @hailbytes/sbom-diff
# or use directly via npx
npx @hailbytes/sbom-diff old.json new.json# Compare two SBOMs and print a human-readable report
npx @hailbytes/sbom-diff old.json new.json
# Output as JSON
npx @hailbytes/sbom-diff old.json new.json --format json
# Output as Markdown (great for PR comments)
npx @hailbytes/sbom-diff old.json new.json --format markdown
# Fail the build (exit code 3) if any new high or critical CVE appears
npx @hailbytes/sbom-diff old.json new.json --fail-on high
# Show help or print the installed version
npx @hailbytes/sbom-diff --help
npx @hailbytes/sbom-diff --versionUse --fail-on to turn the diff into a pass/fail gate. When the policy is
triggered, the report is still printed and the process exits with code 3, so
your pipeline stops on risky changes:
--fail-on |
Fails when… |
|---|---|
none (default) |
never — always exits 0 |
any |
any new CVE is introduced |
low / medium / high / critical |
a new CVE appears at or above that severity |
VEX-aware: CycloneDX vulnerabilities whose analysis.state is not_affected
or false_positive are treated as documented suppressions and never trip the
gate — that is the whole point of VEX. They still appear in the report (tagged
(VEX: not_affected)) so the audit trail is complete, but they won't fail your
build.
# GitHub Actions example
- name: Gate on new high-severity CVEs
run: npx @hailbytes/sbom-diff sbom.base.json sbom.pr.json --fail-on highNote: the gate can only see vulnerabilities that are embedded in the SBOMs you compare. SPDX 2.x has no vulnerability field, and the default output of common CycloneDX generators omits one, so
--fail-onhas nothing to evaluate for those inputs and will pass. When a gate is armed but neither SBOM carries vulnerability data, the CLI prints a warning tostderrso a green result is never mistaken for "no new CVEs". To enable CVE gating, feed SBOMs that include a CycloneDX 1.4+vulnerabilitieslist (e.g. from a scan/VEX step).
import { readFile } from 'node:fs/promises';
import { parse, diff, renderReport } from '@hailbytes/sbom-diff';
// parse() accepts a JSON string (or already-parsed object) and auto-detects
// the CycloneDX/SPDX format. diff() compares two parsed SBOMs synchronously.
const oldSBOM = parse(await readFile('old.cdx.json', 'utf-8'));
const newSBOM = parse(await readFile('new.cdx.json', 'utf-8'));
const report = diff(oldSBOM, newSBOM);
console.log(report.added); // Component[] — newly added packages
console.log(report.removed); // Component[] — packages removed
console.log(report.upgraded); // VersionChange[] — { component, from, to, isMajorBump }
console.log(report.licenseChanges); // LicenseChange[] — { component, from, to } (e.g. MIT → GPL-3.0)
console.log(report.newCVEs); // CVEEntry[] — vulnerabilities new in the latest SBOM
// Or render a ready-made report in text, JSON, or markdown:
console.log(renderReport(report, 'markdown'));Security engineers, DevSecOps teams, and supply-chain risk analysts who need to track dependency changes between software releases, detect newly introduced CVEs, and produce auditable SBOM diff reports for compliance evidence.
@hailbytes/caiq-lite— CSA CAIQ-Lite schema and validator@hailbytes/asm-scope-parser— Attack surface scope parsing- HailBytes
Part of the HailBytes open-source security toolkit.