An SBOM (software bill of materials) is a machine-readable inventory of everything your software is built from: the open-source and commercial libraries, their exact versions, who supplies them and how they depend on each other. CISA puts it simply: an SBOM is "a nested inventory, a list of ingredients that make up software components."

That sounds like paperwork, and for years it was treated that way. Then a few large supply chain incidents made one question painfully expensive to answer: "Are we running the vulnerable version of this library, and where?" An SBOM is the file that lets you answer that in minutes instead of weeks. This guide covers what goes inside one, why regulators now ask for it, the two main formats (CycloneDX vs SPDX), how to generate one and, just as important, what an SBOM does not do.

What is an SBOM, exactly?

Think of the label on a food package. It lists ingredients, not whether each ingredient is safe for you. An SBOM does the same for software. For every component, it records at least a name, a version and an identifier, plus the relationships between components: your app depends on a web framework, which depends on a logging library, which depends on something else three levels down.

In July 2021 the US NTIA published "The Minimum Elements For a Software Bill of Materials". Its baseline data fields are still the best mental model of what an SBOM should contain:

  • Supplier name: who created or maintains the component.
  • Component name and version.
  • Other unique identifiers, such as a Package URL (purl) like pkg:npm/[email protected] or a CPE.
  • Dependency relationship: which component includes which.
  • Author of the SBOM data and a timestamp.

CISA has since been working on updated minimum elements, but the core idea has not changed: identify every component precisely enough that a machine can match it against a vulnerability database or a license list.

Direct vs transitive dependencies

Your package.json or requirements.txt lists maybe 30 direct dependencies. Your lockfile often lists hundreds, because each of those pulls in its own dependencies. A useful SBOM captures the full tree, because vulnerabilities do not care whether you imported a package on purpose. Here is what a single component looks like in a CycloneDX JSON SBOM:

{
  "type": "library",
  "name": "log4j-core",
  "version": "2.14.1",
  "purl": "pkg:maven/org.apache.logging.log4j/[email protected]",
  "licenses": [{ "license": { "id": "Apache-2.0" } }]
}

Why SBOMs matter now

Supply chain attacks and "where are we affected?"

When Log4Shell (CVE-2021-44228) was disclosed in December 2021, most teams did not struggle to understand the bug. They struggled to find it. Log4j was often a transitive dependency buried inside another library, inside a container image, inside a service nobody had touched in a year. Organizations with an up-to-date inventory could search it. Everyone else grepped repositories and asked teams to check by hand.

That is the core value of an SBOM: it turns "are we affected?" from an investigation into a query. The same logic applies to malicious packages, typosquatting and compromised maintainers. You cannot respond to a risk in a component you do not know you ship. This is also why SBOMs sit alongside software composition analysis in any serious DevSecOps program.

US Executive Order 14028

On May 12, 2021, the US government issued Executive Order 14028, "Improving the Nation's Cybersecurity". One of its goals was enhancing software supply chain security, and it directed NTIA to publish the minimum elements for an SBOM, which NTIA did on July 12, 2021. The practical effect was that SBOMs moved from a niche best practice to something federal buyers started asking software vendors for.

EU Cyber Resilience Act

The EU Cyber Resilience Act (CRA) entered into force on 10 December 2024. Its reporting obligations for actively exploited vulnerabilities apply from 11 September 2026, and its main obligations apply from 11 December 2027. Annex I, Part II requires manufacturers to identify and document the components in their products, including by drawing up an SBOM in a commonly used, machine-readable format covering at least the top-level dependencies. If you sell software or connected products in the EU, an SBOM is becoming part of the product, not an optional extra.

SBOM formats: CycloneDX vs SPDX

Two open formats dominate. Both are machine-readable, both are widely supported, and for most teams the choice matters less than generating an SBOM at all. Still, they come from different places.

SPDX

SPDX (Software Package Data Exchange) is an open source project hosted by the Linux Foundation. It started with license compliance, which is why it ships the SPDX License List and license expression syntax that most of the ecosystem now uses (MIT, Apache-2.0, GPL-3.0-or-later). The specification is recognized as ISO/IEC 5962:2021. SPDX 3.0, released in April 2024, added profiles for Security, Build, Dataset and AI.

CycloneDX

CycloneDX is driven by the OWASP Foundation and the Ecma International Technical Committee TC54, and is standardized as ECMA-424. It was designed with security use cases front and center. Beyond SBOMs it covers SaaSBOM, CBOM (cryptography), HBOM (hardware), AI/ML-BOM and VEX (Vulnerability Exploitability eXchange), a way to state whether a known vulnerability actually affects your product.

DimensionSPDXCycloneDX
StewardLinux FoundationOWASP and Ecma TC54
Formal standardISO/IEC 5962:2021ECMA-424
OriginLicense complianceApplication security
StrengthsLicense data, legal review, broad ecosystemVulnerability workflows, VEX, extra BOM types
Common file names*.spdx.jsonbom.json, *.cdx.json

Practical rule: if your main consumer is a legal or procurement team, SPDX is a natural fit. If your main consumer is a vulnerability management pipeline, CycloneDX often is. If a customer or regulator asks for a specific format, use that one. Tools like Syft can emit both from the same scan.

How to generate an SBOM

Syft

Syft, from Anchore, is a CLI that generates SBOMs from container images, filesystems and archives, across dozens of ecosystems (npm, PyPI, Maven, Go, Cargo, Alpine, Debian, RPM and more):

# SBOM of a source directory, CycloneDX JSON
syft ./my-project -o cyclonedx-json=./bom.cdx.json

# SBOM of a container image, both formats at once
syft my-app:1.4.2 -o spdx-json=./sbom.spdx.json -o cyclonedx-json=./bom.cdx.json

cdxgen

cdxgen is an OWASP Foundation project that produces CycloneDX BOMs from local paths, git repositories, purls and container images, and can also export SPDX 3.0.1 JSON-LD:

cdxgen -o bom.json .

GitHub dependency graph export

If your code lives on GitHub, you can export the current dependency graph of a repository as an SPDX 2.3 file: open the repository, go to Insights, then Dependency graph, and click Export SBOM. There is also a REST API endpoint for the same export, which is handy for automation. Keep in mind that it reflects what the dependency graph knows from your manifests and lockfiles, not what ends up inside your built container.

Source SBOM vs build SBOM

Where you generate the SBOM changes what it contains. A source SBOM, built from lockfiles, tells you what your application declares. A build or image SBOM, built from the final artifact, also includes OS packages in the base image and anything copied in during the build. For a deployed service, the image SBOM is closer to reality. The best practice is to generate it in CI for every release and store it next to the artifact, so each version you ship has a matching inventory.

How to use an SBOM

Vulnerability matching (CVE and OSV)

An SBOM becomes useful when you match it against vulnerability data. Two open source options read SBOM files directly:

# Grype: scan an existing SBOM
grype sbom:./bom.cdx.json

# OSV-Scanner: scan an SBOM against the OSV database
osv-scanner scan source -L ./sbom.spdx.json

OSV-Scanner recognizes SBOMs by file name, so stick to the conventions (*.spdx.json, bom.json, *.cdx.json). Because you stored an SBOM per release, you can re-scan old releases when a new CVE appears, without rebuilding anything. That is the "query instead of investigation" payoff.

License compliance

Each component can carry an SPDX license identifier. Legal teams use this to spot copyleft licenses in a proprietary product, missing licenses, or components whose terms conflict with how you distribute your software.

Customer and regulator requests

Security questionnaires increasingly ask for an SBOM, and the CRA will require one as part of technical documentation. Pairing the SBOM with VEX statements lets you tell a customer "yes, that CVE is in a component we ship, but the vulnerable function is not reachable in our product" in a structured way instead of a long email thread.

Limits of an SBOM

  • It is a snapshot. An SBOM describes one build at one point in time. New CVEs are published every day against components that were considered clean yesterday, so the value comes from re-matching, not from the file alone.
  • It is only as good as the generator. Vendored code, copied snippets, statically linked binaries and custom build steps are easy to miss. Two tools can produce different SBOMs for the same project.
  • It says nothing about exploitability. Listing a vulnerable version does not mean your code calls the vulnerable function. Without reachability analysis or VEX, teams drown in findings that do not matter.
  • It does not cover your own code. Injection flaws, broken access control and the other issues in the OWASP Top 10 live in code you wrote, which needs AI SAST or other static analysis (see SAST vs DAST).
  • It does not cover secrets or configuration. A leaked API key or an over-privileged CI workflow will never appear in a bill of materials. That is the job of secret scanning tools, such as a secret scanner that also covers git history, and configuration checks.

Where Nurbak fits

To be clear about scope: Nurbak does not generate or export SBOM files. If you need an SBOM for a customer or for CRA documentation, use Syft, cdxgen or the GitHub export described above.

What Nurbak does is the part many teams actually wanted from their SBOM in the first place: when you connect GitHub and scan a repository, it reads your lockfiles, checks each dependency against known vulnerabilities in OSV and reports the vulnerable packages together with the fixed version to upgrade to. In the same scan, its own self-hosted AI model analyzes your code for exploitable vulnerabilities with file and line (the analysis does not send your code to OpenAI or Anthropic), flags GitHub Actions, Docker, Terraform and Kubernetes misconfigurations and detects secrets in current code and git history, all summarized in a 0 to 100 score. The free scan shows the three most important findings in full. See how the dependency part works on the software composition analysis page, or run the broader GitHub security scanner.

Bottom line

An SBOM is the ingredient list of your software. It will not make your product secure by itself, but it makes the most common supply chain question answerable in minutes, and regulation on both sides of the Atlantic is turning it into a baseline expectation. Generate one per release in CI, pick CycloneDX or SPDX based on who consumes it, re-match it against vulnerability data continuously, and remember that your own code, your secrets and your configuration need their own checks.

Related reading