CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/sbom-formats

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

Quality

91%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

spdx.mdreferences/

SPDX - Software Package Data Exchange (format reference)

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:

VersionStatusNotable
SPDX 2.3Stable; broadly tooledTag-Value / JSON / YAML / RDF / Spreadsheet; ISO/IEC 5962:2021
SPDX 3.0Recent (2024); growing toolingProfile-based: core + software + AI + dataset + build + security; JSON-LD primary

When SPDX is the right format

  • US Federal procurement context (NIST SP 800-218 + EO 14028 guidance favor SPDX).
  • Linux Foundation member organization workflow.
  • License-compliance focused use case (SPDX has the richest license-expression vocabulary).
  • A consumer (regulator, customer) requires SPDX format specifically.

SPDX 2.3 top-level structure (JSON)

{
  "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"
    }
  ]
}

Required fields per SPDX 2.3

Per spdx-spec:

FieldRequired?Use
spdxVersionyesMust be "SPDX-2.3"
dataLicenseyes"CC0-1.0" (CC0 - the SBOM data itself)
SPDXIDyes"SPDXRef-DOCUMENT"
nameyesHuman-readable doc name
documentNamespaceyesUnique URI per BOM revision
creationInfo.createdyesISO 8601 timestamp
creationInfo.creatorsyesTool / org / person who created
packages[]required for non-empty BOMInventory
relationships[]required (at least DESCRIBES)Dep graph

License expressions

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"

Relationships

The relationships[] block is the dep-graph (SPDX equivalent of CycloneDX's dependencies[]):

RelationshipTypeUse
DESCRIBES / DESCRIBED_BYDocument to top-level package
DEPENDS_ON / DEPENDENCY_OFCompile-time / runtime dep
BUILD_DEPENDENCY_OFBuild-only dep
DEV_DEPENDENCY_OFTest/dev-only dep
RUNTIME_DEPENDENCY_OFRuntime-only dep
OPTIONAL_DEPENDENCY_OFOptional dep
CONTAINS / CONTAINED_BYContainer to contained file/package
GENERATED_FROMSource-of-build
STATIC_LINK / DYNAMIC_LINKLinkage type

Tag-Value format (SPDX-native)

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-myapp

JSON 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.

Validation

# 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/

CI integration

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.json

Worked example

A team must deliver an SPDX 2.3 SBOM to a US Federal procurement consumer for an app that bundles one proprietary component:

  1. Generates via Syft in CI: anchore/sbom-action with format: spdx-json, producing sbom.spdx.json with spdxVersion: "SPDX-2.3", dataLicense: "CC0-1.0", and a unique documentNamespace.
  2. The app package uses a non-standard license, so the team declares it via hasExtractedLicensingInfos and sets licenseConcluded: "LicenseRef-AcmeProprietary"; every third-party package keeps its standard SPDX ID (MIT, etc.).
  3. Adds relationships[]: SPDXRef-DOCUMENT DESCRIBES the app package, and the app DEPENDS_ON each dependency.
  4. Validates: 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.

SPDX anti-patterns

Anti-patternWhy it failsFix
Skip documentNamespaceCan't deduplicate across BOM revisionsGenerate unique URI per BOM
Use SPDX 3.0 with consumer expecting 2.3Tooling incompatStick to SPDX 2.3 unless 3.0 required
Manual license assignment without LicenseRef- for customLicense-expression validation failsUse proper SPDX license ID or LicenseRef-
Skip relationships[] (just packages)No dep-graph; downstream tools degradeAlways include DESCRIBES + DEPENDS_ON
Mix Tag-Value + JSON in same workflowToolchain confusionPick one format per workflow

SPDX limitations

  • SPDX 2.3 vuln support is weaker than CycloneDX 1.6 (no first-class vulnerabilities block - relies on companion VEX docs).
  • License-expression validation is strict; non-standard licenses require LicenseRef- boilerplate.
  • SPDX 3.0 tooling is still maturing; many tools still produce 2.3.
  • Tag-Value parsing is whitespace-sensitive; subtle formatting bugs.

Sources

  • spdx-spec - official specification
  • spdx3-profiles-and-tooling.md - SPDX 3.0 profiles + tooling landscape
  • spdx.dev - landing
  • spdx.org/licenses - license ID list
  • iso.org/standard/81870.html - ISO/IEC 5962:2021 (SPDX 2.2.1 ISO publication)
  • tools.spdx.org - online validator
  • github.com/spdx/tools-python - Python reference impl

SKILL.md

tile.json