cyclonedx-format
Reference for the CycloneDX v1.6 software bill of materials (SBOM) specification - OWASP-curated, security-focused format covering software components, services, dependencies, vulnerabilities, formulation, machine learning models, and SaaS BOMs; supports XML / JSON / Protobuf encodings; per-language generators for npm, pip, Maven, Gradle, Go, etc.; integrates with CI via generate + sign + attest workflow. Use when the user asks to generate or write a software bill of materials / SBOM in CycloneDX form, or when the team adopts CycloneDX as its primary SBOM format (preferred for security-focused use cases vs SPDX's licensing focus).
Install with skills.sh (any agent)
npx skills add testland/qa --skill cyclonedx-formatcyclonedx-format
Overview
CycloneDX is an OWASP-curated, security-focused SBOM format. Per cyclonedx.org/specification/overview (opens in new window), its distinguishing features vs SPDX:
This is a reference skill - defines the schema + tooling landscape; doesn't run scans. Pair with syft-generation to generate CycloneDX-format SBOMs from real codebases.
When to use
For licensing-focused / Linux Foundation contexts, spdx-format is more idiomatic.
How to use
Work the numbered Steps in order: generate the BOM (Steps 1-2), add a VEX-style analysis record per triaged finding (Steps 3, 5), validate against the schema (Step 4), then sign + attest in CI (Step 6). Pin the specVersion your consumer agreed; bump version on each re-issue.
Step 1 - Top-level structure
A minimal CycloneDX 1.6 BOM (JSON):
{
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"metadata": {
"timestamp": "2026-05-06T12:00:00Z",
"tools": [{"vendor": "anchore", "name": "syft", "version": "1.16.0"}],
"component": {
"type": "application",
"name": "my-app",
"version": "1.0.0",
"purl": "pkg:generic/my-app@1.0.0"
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:npm/lodash@4.17.20",
"name": "lodash",
"version": "4.17.20",
"purl": "pkg:npm/lodash@4.17.20",
"licenses": [{"license": {"id": "MIT"}}]
}
],
"dependencies": [
{
"ref": "pkg:generic/my-app@1.0.0",
"dependsOn": ["pkg:npm/lodash@4.17.20"]
}
]
}Step 2 - Required fields per spec
Per cdx-spec (opens in new window):
| Field | Required? | Use |
|---|---|---|
bomFormat | yes | Must be "CycloneDX" |
specVersion | yes | "1.6" (current) / "1.5" / "1.4" |
serialNumber | recommended | URN UUID identifying the BOM |
version | recommended | BOM revision (incremented per re-issue) |
metadata | recommended | Generation context (timestamp, tools, top-level component) |
components[] | required for non-empty BOMs | Inventory of dependencies |
dependencies[] | recommended | Dependency-graph edges via bom-ref |
services[] | optional | Hosted services (SaaS BOM) |
vulnerabilities[] | optional | Per-finding records |
formulation[] | optional | Build metadata |
Component types and per-language native generators are cataloged in references/component-types-and-tooling.md; the purl (Package URL) field is the canonical component identifier.
Step 3 - Vulnerability block (VEX-equivalent)
CycloneDX has first-class vuln support (unlike SPDX which delegates to companion files):
"vulnerabilities": [
{
"id": "CVE-2024-1234",
"source": {"name": "NVD", "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-1234"},
"ratings": [
{"source": {"name": "NVD"}, "severity": "critical", "method": "CVSSv3", "score": 9.8}
],
"cwes": [798],
"description": "Hardcoded credential in lodash sortBy function",
"affects": [{"ref": "pkg:npm/lodash@4.17.20"}],
"analysis": {
"state": "not_affected",
"justification": "code_not_present",
"detail": "Vulnerable function not exported in current build"
}
}
]The analysis.state field uses VEX-equivalent values: resolved, resolved_with_pedigree, exploitable, in_triage, false_positive, not_affected.
Step 4 - Validation
Validate a CycloneDX SBOM against the schema:
# Using cyclonedx-cli (Anchore-equivalent for CycloneDX)
cyclonedx validate --input-file sbom.json --input-version v1_6
# Or via npm
npx @cyclonedx/cyclonedx-bom validate sbom.jsonValidation catches structural issues (missing required fields, invalid PURLs, unknown component types) before publishing.
Step 5 - VEX integration
The Step 3 vulnerabilities[] record IS embedded VEX (Vulnerability Exploitability Exchange, CycloneDX 1.4+). To assert a triaged CVE does not affect the shipped product, extend that same record - deltas only:
This lets downstream consumers filter the false-positive finding instead of re-doing reachability analysis.
Step 6 - CI integration
jobs:
cyclonedx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# Per-language native (recommended for richer SBOM)
- run: npx @cyclonedx/cyclonedx-npm --output-file=sbom.cyclonedx.json
# OR via Syft (broader source coverage)
- uses: anchore/sbom-action@v0
with:
format: cyclonedx-json
output-file: sbom.cyclonedx.json
# Validate
- run: cyclonedx validate --input-file sbom.cyclonedx.json --input-version v1_6
# Sign + attest
- run: cosign attest --predicate sbom.cyclonedx.json --type cyclonedx my-image:1.0Worked example
A Node.js service must ship a CycloneDX SBOM to a security-focused customer. The team:
Result: a schema-valid, attested CycloneDX 1.6 BOM whose embedded VEX lets the customer drop the lodash finding without re-doing reachability analysis.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Skip serialNumber field | Can't deduplicate across re-generations | Generate URN UUID per BOM |
Use metadata.tools[] v1.4 schema in 1.6+ | Schema evolution; tools shape changed | Use metadata.tools.components[] (newer schema) |
Skip dependencies[] block | Loss of dep-graph info; downstream tools degrade | Always include (Step 1) |
| Hand-author CycloneDX | Schema is large; errors easy to introduce | Use generators (references) |
| Skip schema validation | Invalid SBOMs pass into prod; downstream consumers fail | Validate in CI (Step 4) |
Limitations
References
CycloneDX component types and per-language tooling
View source (opens in new window)CycloneDX component types and per-language tooling
Reference tables extracted from cyclonedx-format. See cyclonedx.org/specification/overview (opens in new window) for the source spec.
Component types
Per cdx-spec (opens in new window) common component types:
| Type | Use |
|---|---|
application | Top-level app being described |
library | Code dependency (npm, pip, Maven artifact) |
framework | Application framework (React, Django, Spring) |
container | OCI/Docker container image |
operating-system | OS (Alpine, Ubuntu, etc.) |
firmware | Embedded firmware |
device | Hardware device |
file | Standalone file (script, binary) |
machine-learning-model | ML model (since 1.5) |
data | Dataset (since 1.5) |
cryptographic-asset | Crypto algorithm/key (since 1.6) |
The purl (Package URL) field is the canonical identifier per github.com/package-url/purl-spec (opens in new window).
Per-language native tooling
CycloneDX has per-language native generators (alternative to Syft):
| Language | Tool | Source |
|---|---|---|
| Node.js | @cyclonedx/cyclonedx-npm | github.com/CycloneDX/cyclonedx-node-npm |
| Python | cyclonedx-py (cyclonedx-bom) | github.com/CycloneDX/cyclonedx-python |
| Java/Maven | cyclonedx-maven-plugin | github.com/CycloneDX/cyclonedx-maven-plugin |
| Java/Gradle | cyclonedx-gradle-plugin | github.com/CycloneDX/cyclonedx-gradle-plugin |
| Go | cyclonedx-gomod | github.com/CycloneDX/cyclonedx-gomod |
| .NET | CycloneDX-DOTNET | github.com/CycloneDX/cyclonedx-dotnet |
| Rust | cargo-cyclonedx | github.com/CycloneDX/cyclonedx-rust-cargo |
Per-language tools often produce richer SBOMs than Syft (deeper metadata, language-specific quirks handled).
Related skills
grype-scanning
Scans for vulnerabilities using Anchore Grype: `grype sbom:./sbom.json` / `grype {image}` / `grype dir:./` across OS-package + language-package ecosystems (Alpine / Debian / Ubuntu / RHEL / Amazon Linux / Ruby / Java / JavaScript / Python / .NET / Go / PHP / Rust). `.grype.yaml` per-CVE and per-package ignore rules with mandatory `expires:` dates and reachability justification (the Grype-native suppression path, distinct from standalone VEX document authoring in vex-author); EPSS + KEV + risk-score prioritization; OpenVEX assertion filtering; `--fail-on high/critical` CI gate. Use when the team wants Grype-native vuln scanning, or pairs with Syft (syft-generation) for an SBOM-driven workflow.
sbom-diff
Compares two CycloneDX or SPDX SBOMs to surface net-new, removed, and version-changed components between image or build versions; uses cyclonedx-cli diff for structured output and syft-based generation for the input SBOMs; gates CI on net-new component introduction; enables supply-chain alerting when unexpected dependencies appear across releases. Use when the team needs to detect dependency drift between container image builds, release candidates, or dependency-update branches.
spdx-format
Reference for the SPDX (Software Package Data Exchange) v2.3 + v3.0 SBOM specification - Linux Foundation-curated, license-focused format covering packages, files, snippets, relationships, license declarations, and (in 3.0) AI / dataset / build / security profiles; supports Tag-Value / JSON / YAML / RDF / Spreadsheet encodings; preferred by US Federal procurement (NIST guidance) and Linux distros. Use when the team's SBOM consumer requires SPDX format (federal procurement, Linux Foundation members, license-compliance focus).
syft-generation
Generates Software Bill of Materials (SBOMs) using Anchore Syft - supports container images / directories / archives across OCI / Docker / Singularity formats; output formats CycloneDX-JSON / SPDX-JSON / Syft-JSON / table / GitHub-JSON; pairs with `grype-scanning` for SBOM-driven vuln scanning. Use when the team needs SBOM artifacts for compliance (US EO 14028, EU CRA, FDA medical-device guidance) or as input to vuln scanners.
trivy-image
Configures and runs Trivy for container image scanning: Aqua Security's all-in-one scanner combining vuln + secret + misconfiguration + license detection in one pass; `trivy image {image}` with --severity HIGH,CRITICAL filter; --format sarif/json (incl. scan-embedded CycloneDX; for standalone SBOM generation see syft-generation + cyclonedx-format); .trivyignore CVE suppression file; --ignore-unfixed for actionable filter; --scanners vuln/misconfig/license/secret toggle. Use when the team wants a single tool covering container image security across multiple dimensions, not for producing a standalone CycloneDX SBOM.
vex-author
Authors and validates OpenVEX documents - produces `not_affected`, `affected`, `fixed`, and `under_investigation` statements with justification codes using `vexctl create`; attaches VEX assertions to container images; outputs `.openvex.json` files consumed on a downstream VEX-filter / vulnerability-prioritization path. Use when a scanner flags a CVE that analysis confirms is not exploitable in your deployment, and a machine-readable `not_affected` assertion is needed to suppress false positives without discarding the finding from the audit trail.