Reference for the two SBOM specification families and how to choose between them - CycloneDX v1.6 (OWASP-curated, security-focused: components, services, dependencies, first-class vulnerabilities[] with embedded VEX, formulation, ML/SaaS BOMs; XML / JSON / Protobuf) as the primary format, with SPDX 2.3 + 3.0 (Linux Foundation, license-focused: packages, relationships, license expressions, Tag-Value/JSON encodings, ISO/IEC 5962:2021) covered as a reference. Includes per-language generators, schema validation, sign + attest CI wiring, and the format-choice guidance (CycloneDX for security-focused consumers; SPDX for US Federal procurement, Linux Foundation, and license-compliance contexts). Use when the user asks to write or validate an SBOM in CycloneDX or SPDX form, or the team must pick its SBOM format.
72
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Companion reference for sbom-formats. Consult when the SBOM consumer
requires SPDX (US Federal procurement, Linux Foundation members,
license-compliance focus); the SKILL.md covers CycloneDX and the
format-choice guidance.
SPDX is the Linux Foundation's SBOM standard, originally focused on license compliance. Per spdx.org/specifications:
Two active major versions:
| Version | Status | Notable |
|---|---|---|
| SPDX 2.3 | Stable; broadly tooled | Tag-Value / JSON / YAML / RDF / Spreadsheet; ISO/IEC 5962:2021 |
| SPDX 3.0 | Recent (2024); growing tooling | Profile-based: core + software + AI + dataset + build + security; JSON-LD primary |
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "my-app-1.0.0-sbom",
"documentNamespace": "https://example.com/spdx/my-app/1.0.0",
"creationInfo": {
"created": "2026-05-06T12:00:00Z",
"creators": ["Tool: syft-1.16.0", "Organization: Acme Corp"]
},
"packages": [
{
"SPDXID": "SPDXRef-Package-myapp",
"name": "my-app",
"versionInfo": "1.0.0",
"downloadLocation": "NOASSERTION",
"filesAnalyzed": false,
"licenseConcluded": "Apache-2.0",
"licenseDeclared": "Apache-2.0"
},
{
"SPDXID": "SPDXRef-Package-lodash",
"name": "lodash",
"versionInfo": "4.17.20",
"downloadLocation": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"filesAnalyzed": false,
"licenseConcluded": "MIT",
"licenseDeclared": "MIT"
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relationshipType": "DESCRIBES",
"relatedSpdxElement": "SPDXRef-Package-myapp"
},
{
"spdxElementId": "SPDXRef-Package-myapp",
"relationshipType": "DEPENDS_ON",
"relatedSpdxElement": "SPDXRef-Package-lodash"
}
]
}Per spdx-spec:
| Field | Required? | Use |
|---|---|---|
spdxVersion | yes | Must be "SPDX-2.3" |
dataLicense | yes | "CC0-1.0" (CC0 - the SBOM data itself) |
SPDXID | yes | "SPDXRef-DOCUMENT" |
name | yes | Human-readable doc name |
documentNamespace | yes | Unique URI per BOM revision |
creationInfo.created | yes | ISO 8601 timestamp |
creationInfo.creators | yes | Tool / org / person who created |
packages[] | required for non-empty BOM | Inventory |
relationships[] | required (at least DESCRIBES) | Dep graph |
SPDX is the canonical source for license identifiers (cross-format standard - even CycloneDX uses SPDX license IDs).
"licenseConcluded": "Apache-2.0",
"licenseConcluded": "MIT OR Apache-2.0",
"licenseConcluded": "(MIT AND BSD-3-Clause) OR GPL-2.0-only WITH Classpath-exception-2.0"Full list: spdx.org/licenses (current count ~600+).
The LicenseRef- prefix declares custom licenses:
"hasExtractedLicensingInfos": [{
"licenseId": "LicenseRef-AcmeProprietary",
"extractedText": "Acme Proprietary License Text..."
}],
"licenseConcluded": "LicenseRef-AcmeProprietary"The relationships[] block is the dep-graph (SPDX equivalent of
CycloneDX's dependencies[]):
| RelationshipType | Use |
|---|---|
DESCRIBES / DESCRIBED_BY | Document to top-level package |
DEPENDS_ON / DEPENDENCY_OF | Compile-time / runtime dep |
BUILD_DEPENDENCY_OF | Build-only dep |
DEV_DEPENDENCY_OF | Test/dev-only dep |
RUNTIME_DEPENDENCY_OF | Runtime-only dep |
OPTIONAL_DEPENDENCY_OF | Optional dep |
CONTAINS / CONTAINED_BY | Container to contained file/package |
GENERATED_FROM | Source-of-build |
STATIC_LINK / DYNAMIC_LINK | Linkage type |
Some toolchains use the SPDX Tag-Value format (older but well-tooled):
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: my-app-1.0.0-sbom
DocumentNamespace: https://example.com/spdx/my-app/1.0.0
Creator: Tool: syft-1.16.0
Creator: Organization: Acme Corp
Created: 2026-05-06T12:00:00Z
PackageName: my-app
SPDXID: SPDXRef-Package-myapp
PackageVersion: 1.0.0
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageLicenseConcluded: Apache-2.0
PackageLicenseDeclared: Apache-2.0
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-myappJSON is preferred for new toolchains; Tag-Value persists for legacy integrations.
SPDX 3.0 profiles and the SPDX tooling landscape are cataloged in spdx3-profiles-and-tooling.md; for most teams, stay on SPDX 2.3 unless 3.0 features are required.
# Python spdx-tools
pip install spdx-tools
pyspdxtools --infile sbom.spdx.json --version SPDX-2.3
# Validates structural conformance + license-expression syntax
# Validation via spdx online tool
# Upload to https://tools.spdx.org/app/jobs:
spdx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: anchore/sbom-action@v0
with:
format: spdx-json
output-file: sbom.spdx.json
- run: |
pip install spdx-tools
pyspdxtools --infile sbom.spdx.json --version SPDX-2.3
- uses: actions/upload-artifact@v4
with:
name: spdx-sbom
path: sbom.spdx.jsonA team must deliver an SPDX 2.3 SBOM to a US Federal procurement consumer for an app that bundles one proprietary component:
anchore/sbom-action with
format: spdx-json, producing sbom.spdx.json with
spdxVersion: "SPDX-2.3", dataLicense: "CC0-1.0", and a unique
documentNamespace.hasExtractedLicensingInfos and sets
licenseConcluded: "LicenseRef-AcmeProprietary"; every
third-party package keeps its standard SPDX ID (MIT, etc.).relationships[]: SPDXRef-DOCUMENT DESCRIBES the app
package, and the app DEPENDS_ON each dependency.pyspdxtools --infile sbom.spdx.json --version SPDX-2.3 -
structural + license-expression checks pass.Result: a validated SPDX 2.3 JSON SBOM whose custom license resolves cleanly and whose relationship graph satisfies the federal consumer's format requirement.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Skip documentNamespace | Can't deduplicate across BOM revisions | Generate unique URI per BOM |
| Use SPDX 3.0 with consumer expecting 2.3 | Tooling incompat | Stick to SPDX 2.3 unless 3.0 required |
Manual license assignment without LicenseRef- for custom | License-expression validation fails | Use proper SPDX license ID or LicenseRef- |
Skip relationships[] (just packages) | No dep-graph; downstream tools degrade | Always include DESCRIBES + DEPENDS_ON |
| Mix Tag-Value + JSON in same workflow | Toolchain confusion | Pick one format per workflow |
LicenseRef- boilerplate.