Skip to content
Back to skills

Sbom Formats

ASecurity

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, sc...

  • 10 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 12, 2026
testinggobashnodeexpressgitsecurity

Works with

  • cli

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 12, 2026

npx -y skills add testland/qa --skill sbom-formats --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sbom Formats?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sbom Formats
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/testland-sbom-formats/badge)](https://www.skillsdirectory.com/skills/testland-sbom-formats)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sbom-formats
description: "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."
---

# sbom-formats

## Overview

Two specification families dominate the SBOM landscape. CycloneDX is the
OWASP-curated, security-focused format and this skill's primary subject;
SPDX is the Linux Foundation's license-focused standard, covered in
[references/spdx.md](references/spdx.md).

Per [cyclonedx.org/specification/overview][cdx-spec], CycloneDX's
distinguishing features vs SPDX:

[cdx-spec]: https://cyclonedx.org/specification/overview/

- **Vulnerability schema** - first-class `vulnerabilities[]` block
  with VEX-style status assertions
- **Services + dataflow** - `services[]` block describes service
  endpoints + data flows
- **Formulation** - describes how the software was built (build
  steps, tools, env)
- **ML BOMs (CycloneDX 1.5+)** - first-class ML model + dataset
  components
- **SaaS BOMs** - describes hosted services not just shipped
  artifacts

This is a **reference skill** - defines the schemas + tooling landscape;
doesn't run scans. Pair with `syft-generation` to generate SBOMs in either
format from real codebases.

## Choosing a format

| Signal | Pick |
|---|---|
| Security-focused consumer (vuln tracking, supply-chain attestation) | CycloneDX |
| US Federal procurement (NIST SP 800-218 + EO 14028 guidance) | SPDX ([references/spdx.md](references/spdx.md)) |
| License-compliance focus (richest license-expression vocabulary) | SPDX |
| Linux Foundation member organization workflow | SPDX |
| EU consumers / broad modern tooling | CycloneDX (most common) |
| Consumer dictates the format | Whatever the consumer requires |

When no consumer constraint exists, CycloneDX is the default here: its
embedded VEX (`vulnerabilities[].analysis`) feeds the triage workflow
directly. Generating both (Syft emits either) satisfies mixed audiences.
Note SPDX license IDs are the cross-format standard - even CycloneDX
license blocks use them.

## When to use

- The team adopts CycloneDX as the primary SBOM format, or must pick a
  format (see Choosing a format).
- The use case is security-focused (vuln tracking, supply-chain
  attestation) over licensing-focused.
- A consumer (vendor, customer, regulator) requires CycloneDX or SPDX
  format specifically (SPDX: [references/spdx.md](references/spdx.md)).
- Per-language CycloneDX-native tooling is preferred over Syft+convert.

## 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.
For an SPDX consumer, follow [references/spdx.md](references/spdx.md)
instead.

## Step 1 - Top-level structure

A minimal CycloneDX 1.6 BOM (JSON):

```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][cdx-spec]:

| 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](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):

```json
"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:

```bash
# Using cyclonedx-cli
cyclonedx validate --input-file sbom.json --input-version v1_6

# Or via npm
npx @cyclonedx/cyclonedx-bom validate sbom.json
```

Validation catches structural issues (missing required fields,
invalid PURLs, unknown component types) before publishing. For SPDX
validation (`pyspdxtools`), see [references/spdx.md](references/spdx.md).

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

- `analysis.justification: "vulnerable_code_not_in_execute_path"` with a
  concrete `analysis.detail` (e.g. "vulnerable parser only invoked under
  `--debug`; production builds disable it").
- `analysis.response: ["will_not_fix"]` - the planned action.

This lets downstream consumers filter the false-positive finding instead
of re-doing reachability analysis.

## Step 6 - CI integration

```yaml
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.0
```

## Worked example

A Node.js service must ship a CycloneDX SBOM to a security-focused
customer. The team:

1. Generates the BOM natively:
   `npx @cyclonedx/cyclonedx-npm --output-file=sbom.cyclonedx.json`.
   Output is `bomFormat: "CycloneDX"`, `specVersion: "1.6"`, with a
   `components[]` entry per dependency (each carrying a `purl`) and a
   `dependencies[]` edge list.
2. A scan flags `CVE-2024-1234` on `pkg:npm/lodash@4.17.20`. Triage
   shows the vulnerable function is not in the execute path, so the
   team adds a `vulnerabilities[]` record with
   `analysis.state: "not_affected"` and
   `justification: "vulnerable_code_not_in_execute_path"` (Step 3).
3. Validates:
   `cyclonedx validate --input-file sbom.cyclonedx.json --input-version v1_6` - passes.
4. Attests to the image:
   `cosign attest --predicate sbom.cyclonedx.json --type cyclonedx my-image:1.0`.

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](references/component-types-and-tooling.md)) |
| Skip schema validation | Invalid SBOMs pass into prod; downstream consumers fail | Validate in CI (Step 4) |
| Pick format by tooling habit, not consumer | Consumer rejects the delivery | Format-choice table (Choosing a format) |

## Limitations

- Both specs are large + evolve; pin schema version per consumer
  agreement.
- Per-language tools have varying quality; some are community-maintained
  + occasionally lag releases.
- VEX assertions are only as good as the analysis behind them;
  unfounded `not_affected` claims are worse than no claim.
- ML / SaaS BOM features are newer (CycloneDX 1.5+) and not all tooling
  supports them.
- SPDX-specific limitations (weaker vuln support, strict license
  expressions, 3.0 tooling maturity) are in
  [references/spdx.md](references/spdx.md).

## References

- [cdx-spec][cdx-spec] - official CycloneDX specification
- [references/spdx.md](references/spdx.md) - SPDX 2.3 + 3.0 format reference
- [references/component-types-and-tooling.md](references/component-types-and-tooling.md) - CycloneDX component types + per-language native tooling
- [references/spdx3-profiles-and-tooling.md](references/spdx3-profiles-and-tooling.md) - SPDX 3.0 profiles + tooling landscape
- cyclonedx.org - landing
- github.com/CycloneDX - org with per-language tools
- github.com/package-url/purl-spec - Package URL spec
- openvex.dev - OpenVEX standalone spec (compatible with CycloneDX
  1.4+ embedded VEX)
- `syft-generation`,
  `trivy-image`,
  `vex-author` - sister tools

Files in this skill

  • .tessl-plugin/plugin.json943 B
  • SKILL.md10.9 KB
  • references/component-types-and-tooling.md1.8 KB
  • references/spdx.md8.1 KB
  • references/spdx3-profiles-and-tooling.md1.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.