SBOMs Explained: SPDX, CycloneDX and Why the Software Bill of Materials Is Now Table Stakes

SBOMs Explained: SPDX, CycloneDX and Why the Software Bill of Materials Is Now Table Stakes

📋 Key Takeaways
  • An SBOM—Software Bill of Materials—is a machine-readable inventory of every component, library, dependency, and license inside a piece of software.
  • The traditional software acquisition playbook assumed you could trust your vendors.
  • An SBOM is not a text file of library names.
  • Two formats dominate, and both are standards—this is not a vendor lock-in fight.
10 min read · 1,824 words
Educational & Ethical Use Only — This article is provided for educational and ethical cybersecurity research purposes only. The techniques described should only be used on systems you own or have explicit permission to test. Always follow responsible disclosure and the laws applicable to you. Mitigations are included so engineers can harden real systems.
Security· 10 min read

🔎 Last updated · Editorial policy · Report an error

TL;DR: What Is an SBOM and Why Does It Matter Now?

An SBOM—Software Bill of Materials—is a machine-readable inventory of every component, library, dependency, and license inside a piece of software. Think ingredients label, but for binaries. After SolarWinds, Log4Shell, and a wave of supply-chain regulation starting with Executive Order 14028, producing and consuming SBOMs stopped being a maturity-project nice-to-have and became table stakes. If you ship software—or buy it—you need one.

Why SBOMs Became Non-Negotiable: SolarWinds, Log4Shell, and the Executive Order

The traditional software acquisition playbook assumed you could trust your vendors. The SolarWinds SUNBURST campaign of December 2020 shredded that assumption: attackers compromised the build pipeline itself and pushed trojanized updates to roughly 18,000 customers. You cannot defend against what you cannot see—and nobody, including SolarWinds, had a complete component inventory of their own product.

Then Log4Shell (CVE-2021-44228) landed in December 2021 and made the cost of that blindness concrete. Organizations spent weeks crawling spreadsheets and running ad-hoc greps across codebases to answer one question: do we run a vulnerable version of Log4j? Teams with accurate SBOMs answered it in minutes.

Regulators noticed. In May 2021, Executive Order 14028 directed the U.S. federal government to improve software supply-chain security, explicitly calling for SBOMs. In September 2022, OMB memorandum M-22-18 made it mandatory: any software producer selling to federal agencies must provide SBOMs following the NTIA minimum elements. CISA has since built an entire SBOM practice area around it—see cisa.gov/sbom—and the EU Cyber Resilience Act pushes the same direction globally. The mandate is real, and it’s expanding.

SBOM Fundamentals: What Goes Into a Bill of Materials

An SBOM is not a text file of library names. The NTIA minimum elements define the baseline every valid SBOM must carry:

  • Supplier name — who produced the component
  • Component name — the canonical package or library name
  • Version — the exact version string
  • Unique identifiers — hashes, PURLs (Package URLs), or SPDX IDs
  • Dependency relationships — which components are upstream/downstream of others
  • SBOM author — who generated the document and when

Richer SBOMs add license identifiers (critical for compliance teams), file-level hashes, and completeness metadata. The dependency graph is the part most people underappreciate—knowing that your application pulls lodash@4.17.20 matters less than knowing how it got there, because that’s what tells you what to patch or pin when the next transitive-dependency CVE drops.

SPDX vs CycloneDX: The Two Formats Compared

Two formats dominate, and both are standards—this is not a vendor lock-in fight. The Linux Foundation’s SPDX (Software Package Data Exchange) is an ISO standard (ISO/IEC 5962:2021) that grew out of license compliance work. CycloneDX originated at OWASP with security operations as its design center.

Dimension SPDX CycloneDX
Origin / steward Linux Foundation, ISO/IEC 5962:2021 OWASP, now OWASP Foundation
Original focus License and compliance Security and risk
Native vulnerability support Bolted on (external refs, VEX profiles) First-class: CVSS, CWE, vulnerability objects in-spec
Serializations JSON, tag-value, RDF, XML, YAML, spreadsheets JSON, XML, protobuf
Tooling ecosystem Strong in compliance/scanning tools Strong in security tooling (Syft, Grype, Trivy, Dependency-Track)
Pick it when Licensing, procurement, regulatory compliance Vulnerability management, incident response, SBOM-as-input-to-scanning

The practical answer for most security teams: produce both, automate both, treat CycloneDX as your operational format and SPDX as your compliance export. You’re attacking a metadata problem—wrapped in procurement logic—so don’t let format debates delay adoption.

SPDX in Practice: Structure, Formats, and Example Snippets

SPDX documents describe packages with unique SPDX IDs (SPDXRef-...) and link them via relationship entries. A trimmed SPDX JSON excerpt:

{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "myapp-1.0.0",
  "creationInfo": {
    "created": "2024-11-03T10:15:00Z",
    "creators": ["Tool: syft-1.18.0"]
  },
  "packages": [
    {
      "SPDXID": "SPDXRef-Package-log4j-core",
      "name": "log4j-core",
      "versionInfo": "2.14.1",
      "licenseConcluded": "Apache-2.0",
      "externalRefs": [
        {
          "referenceCategory": "PACKAGE-MANAGER",
          "referenceType": "purl",
          "referenceLocator": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1"
        }
      ]
    }
  ],
  "relationships": [
    {
      "spdxElementId": "SPDXRef-DOCUMENT",
      "relationshipType": "DESCRIBES",
      "relatedSpdxElement": "SPDXRef-Package-myapp"
    },
    {
      "spdxElementId": "SPDXRef-Package-myapp",
      "relationshipType": "DEPENDS_ON",
      "relatedSpdxElement": "SPDXRef-Package-log4j-core"
    }
  ]
}

The tag-value format is the classic SPDX serialization—SPDXVersion: SPDX-2.3, PackageName: log4j-core, one key-value pair per line—and it’s still what some legacy compliance tooling expects.

CycloneDX in Practice: Structure and Example Snippets

CycloneDX centers on bom-ref identifiers and Package URLs (purl) for unambiguous component identification—and, unlike SPDX, vulnerabilities live in the spec itself:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "serialNumber": "urn:uuid:1b6f1a7e-8f9c-4d2a-9f3b-7c2e1a4b5d6f",
  "version": 1,
  "metadata": {
    "tools": [{"vendor": "Anchore", "name": "syft", "version": "1.18.0"}]
  },
  "components": [
    {
      "bom-ref": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
      "type": "library",
      "name": "log4j-core",
      "version": "2.14.1",
      "purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
      "licenses": [{"license": {"id": "Apache-2.0"}}]
    }
  ],
  "vulnerabilities": [
    {
      "id": "CVE-2021-44228",
      "source": {"name": "NVD"},
      "ratings": [{"severity": "critical", "score": 10.0}],
      "affects": [{"ref": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1"}]
    }
  ]
}

That vulnerability block is the whole reason security teams lean CycloneDX: SBOM and vuln data in one document, consumable by tools like OWASP Dependency-Track.

Generating an SBOM with Syft: Hands-On Walkthrough

Syft from Anchore is the de facto open-source CLI for SBOM generation. It catalogs container images, filesystems, archives, and lockfiles. Install and run:

# Install
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

# Container image (remote, no Docker required)
syft nginx:1.25 -o cyclonedx-json > sbom.cdx.json
syft nginx:1.25 -o spdx-json > sbom.spdx.json

# Human-readable output
syft nginx:1.25

# A repository directory
syft dir:./my-app -o cyclonedx-json

# Just a lockfile
syft path:./package-lock.json -o cyclonedx-json

# Include file-level hashes (bigger, slower, more complete)
syft nginx:1.25 --scope all-layers -o cyclonedx-json

Typical output enumerates OS packages (dpkg, apk, rpm), language packages (npm, pip, Maven, Go modules), and their versions—hundreds of rows for a trivially small image. That count is the point: your “simple” Alpine-based container carries far more attack surface than its Dockerfile suggests.

From SBOM to Action: VulnOps with Grype

An SBOM you generate and never query is shelfware. Grype consumes Syft’s output and matches it against vulnerability feeds (NVD, GitHub Security Advisories, OS distro trackers):

# Scan an image directly (Syft under the hood)
grype nginx:1.25

# Or use your stored SBOM as the input
grype sbom:sbom.cdx.json

# Filter to high and critical
grype sbom:sbom.cdx.json --only-fixed --fail-on high

# Suppress accepted findings
grype sbom:sbom.cdx.json -o json --file report.json
grype sbom:sbom.cdx.json --ignore-query "artifact.name=openssl,cve=CVE-2023-0286"

Each finding carries severity, CVSS score, and fix availability. The --fail-on flag plus an allowlist file turns this into a CI gate: block merges that introduce critical CVEs, suppress vetted-and-unfixable findings with documented rationale, and re-scan on every build. Wire it in as a pipeline step and you’ve converted a point-in-time artifact into a continuous control.

Cutting the Noise with VEX: Machine-Readable Vulnerability Exploitability Statements

Raw vulnerability matching drowns you in false positives—findings for vulnerable code paths you never execute. VEX (Vulnerability Exploitability eXchange) fixes this with machine-readable statements about whether each CVE actually affects your product. Every VEX statement carries one of four impact statuses:

  • not_affected — the vulnerable component is present but not exploitable (with justification)
  • affected — yes, you need to act
  • fixed — it was vulnerable, patched in this version
  • under_investigation — analysis in progress

Two formats matter: CISA’s VEX work built on CSAF (the OASIS Common Security Advisory Framework), and OpenVEX, a lightweight, minimal spec purpose-built for SBOM integration. Both CycloneDX and SPDX now support VEX natively—CycloneDX 1.4+ via status vocabularies, SPDX 3.0 via its security profile. A not_affected statement with a valid justification is the difference between 400 findings and 12 actionable ones.

SBOMs for Blue Teamers: Incident Response and CTF Applications

When the next Log4Shell lands, your incident response question is “where does this component exist in our estate, and at what versions?” With a central SBOM registry, that’s a grep or a Dependency-Track query instead of a fire drill:

# Every asset shipping log4j-core?
jq -r '.components[] | select(.name=="log4j-core") | .version' sbom-*.cdx.json | sort -u

For practitioners building skills, run supply-chain exercises in your lab or CTF practice: generate SBOMs for a deliberately vulnerable image, plant an outdated package, and time how fast you can trace it via its purl and dependency path. Tools like OWASP Dependency-Track make a great self-hosted target—it ingests CycloneDX continuously and alerts on new CVEs against stored BOMs. Blue teamers who internalize this workflow turn supply-chain disclosure chaos into a lookup.

Operational Pitfalls: Stale SBOMs, Coverage Gaps, and Tooling Limits

Honest assessment time—SBOMs have real limitations:

  • Generator-dependent accuracy. Two tools scanning the same image produce different BOMs. Binary-only components, vendored code, and stripped dependencies are frequent blind spots. Cross-check with a second generator for critical assets.
  • Transitive dependency gaps. Lockfile-based generation misses system libraries; image scanning misses source-level dev dependencies. Choose scope deliberately.
  • Staleness. An SBOM is a snapshot. If it’s not regenerated in CI on every build, it’s already wrong.
  • No exploitation context. An SBOM tells you a vulnerable component exists—not whether it’s reachable. Pair it with VEX, reachability analysis, and KEV-list prioritization before triaging.

Adoption Checklist: Making SBOMs Table Stakes in Your Org

  • Require SBOMs (CycloneDX or SPDX, NTIA minimum elements) from every software vendor in procurement contracts—this is already law for U.S. federal suppliers under M-22-18.
  • Automate generation with Syft (or Trivy, or CDXgen) in CI on every build—no manual exports.
  • Store all SBOMs in a central registry (Dependency-Track, Guac, or an object store + index) with unique build linkage.
  • Wire Grype or equivalent scanning against stored SBOMs, with severity-based CI gates and allowlists.
  • Adopt VEX to suppress non-exploitable findings and document risk acceptances.
  • Rehearse: run a tabletop where a major CVE drops and time your “are we exposed?” answer. If it’s not under 30 minutes, fix the workflow—not the people.

SBOMs won’t stop supply-chain attacks. But like Zero Trust, they change your position from blind to informed—and when the next CVE-2021-44228-grade event hits, informed is the side you want to be on.

Frequently Asked Questions

What is an SBOM in simple terms?

A machine-readable ingredient list of all software components, versions, licenses, and dependencies in a product—like a nutrition label for software.

Should I use SPDX or CycloneDX?

CycloneDX is generally preferred for security use cases; SPDX for licensing and compliance. Many organizations produce both from the same scanning pipeline.

Is an SBOM the same as a dependency manifest?

No—lockfiles like package-lock.json cover one language ecosystem. SBOMs span compiled artifacts, OS packages, and system libraries across your whole build.

How do Syft and Grype work together?

Syft generates the SBOM inventory; Grype matches that inventory against vulnerability databases to surface known CVEs. One produces the “what’s in it,” the other answers “what’s broken in it.”

What is a VEX statement?

A machine-readable statement declaring whether a listed vulnerability actually affects your product (affected, not_affected, fixed, under_investigation)—cutting alert noise dramatically.

Hmmnm
Published by Hmmnm

Hands-on cybersecurity tutorials, CVE breakdowns, and guided learning paths — written and lab-tested by the Hmmnm team.

Keep going — the structured way
This post is one step. The learning paths chain the next ones for you, with progress tracking and no account needed.
Follow a learning path →

Prabhu Kalyan Samal

Application Security Consultant and founder of Hmmnm. Certified Red Team Operator, Burp Suite Certified Practitioner, eWPTX, CompTIA SecurityX and Azure Security Engineer. Writes hands-on labs and threat analysis on web, cloud and AI-agent security.