How to Generate an SBOM: 12 Steps, 90 Min [2026]

Software supply chain attacks hit a new pace in 2026. In early August, a self-propagating npm worm known as ChainDrop tore through more than 400 packages and racked up billions of monthly downloads before most teams even knew the libraries were compromised. A few weeks earlier, attackers hijacked the release pipeline for four core AsyncAPI GitHub repositories and slipped trojanized packages into the wild. Neither incident was exotic. Both were the kind of thing a Software Bill of Materials (SBOM) is built to catch fast, once you actually have one wired into your pipeline.

An SBOM is a machine-readable inventory of every component, library, and dependency inside a piece of software, plus the relationships between them. Think of it as an ingredient label for code. When a vulnerability like a malicious npm version or a poisoned Rust crate turns up, an SBOM lets you query “do any of my applications contain this exact version?” in seconds instead of days. That single capability is why regulators on both sides of the Atlantic have turned SBOMs from a nice-to-have into a paper trail auditors will ask for.

This tutorial walks through generating, validating, and operationalizing SBOMs using the same open-source tools that dominate the space right now: Syft, Grype, Trivy, and Dependency-Track. By the end you will have a working pipeline that produces a CycloneDX or SPDX SBOM on every build, scans it for known vulnerabilities, and stores the results somewhere your security team can actually query.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

Why SBOMs matter more in 2026 than they did a year ago

Two regulatory tracks converged this year. In the US, the Cybersecurity and Infrastructure Security Agency (CISA) published its 2026 Minimum Elements for a Software Bill of Materials in July, formally replacing the 2021 NTIA baseline that most tooling still targets. The new guidance roughly doubles the required data set, splitting it into SBOM Metadata (fields describing the document itself, like the tool name, tool version, and a signature from the SBOM author) and Component Data (fields describing each piece of software, including cryptographic hashes and license identifiers). If your organization sells to the federal government or works with a contractor who does, this is the baseline that now matters, not the 2021 version most existing tutorials still reference.

In the European Union, the Cyber Resilience Act (CRA) introduces the first legal requirement for manufacturers to generate, maintain, and share SBOMs for any product with digital elements sold in the EU. Reporting obligations, including notification of actively exploited vulnerabilities, start September 11, 2026. The core SBOM requirement itself becomes fully enforceable on December 11, 2027, which makes 2026 the year organizations are expected to get their generation and lifecycle processes in shape rather than scrambling the month before enforcement hits. The European Union Agency for Cybersecurity (ENISA) reported in its 2026 SBOM Adoption State of Play that 78% of surveyed organizations had already begun implementation work, with 79% expecting to hit the required maturity level before the deadline.

The uncomfortable number sitting underneath all of that policy activity: an empirical scan of more than 26,000 popular GitHub repositories found that under 1% actually ship a policy-compliant SBOM file today. Everyone is talking about SBOMs. Almost nobody’s open-source dependency tree is actually documented. That gap is the opportunity this tutorial closes. The official guidance from the National Institute of Standards and Technology and the European Commission’s Cyber Resilience Act page are worth bookmarking directly, since minimum-element requirements get revised roughly once a year and third-party summaries lag behind.

Recent supply chain incidents SBOMs would have caught faster

The abstract case for SBOMs gets a lot more concrete once you line up what actually happened this year. The ChainDrop npm worm, discovered in early August 2026, compromised more than 400 packages and over 1,300 versions, including widely used libraries such as keyv and flat-cache, reaching packages with multi-billion monthly downloads in under four hours of propagation. An organization with an up-to-date SBOM inventory could query every tracked application for the exact compromised versions in minutes; without one, the standard response is a frantic, ecosystem-wide grep through lockfiles across every repository the company owns.

Two other incidents from mid-2026 make the same point from different ecosystems. In July, attackers compromised the release pipeline for four core AsyncAPI GitHub repositories and published five trojanized npm packages, including tampered versions of @asyncapi/generator and @asyncapi/specs. That same month, a campaign dubbed SleeperGem injected malicious RubyGems, including tampered versions of a Git credential manager gem, to deliver secondary payloads to developer machines. In August, a separate attack targeted the Rust ecosystem through a malicious proc-macro1 crate that reconstructed obfuscated command-and-control addresses and disabled TLS verification on infected machines. None of these three incidents involved the same package registry, the same language, or the same attacker group. What they share is that in each case, the organizations best positioned to respond quickly were the ones that could answer “do we use this exact component and version” without manually inspecting every repository by hand.

Prerequisites and versions

You do not need specialized hardware for this tutorial, just a machine that can run containers and a shell. Here is what to have installed before you start, with the current versions as of September 2026:

ToolVersion used in this tutorialPurposeLicense
Syftv1.51.1Generates the SBOM from source, container images, or filesystemsApache 2.0 (free)
Grypev0.118.0Scans an SBOM or image for known vulnerabilitiesApache 2.0 (free)
Trivyv0.74.0All-in-one scanner; also generates and consumes SBOMsApache 2.0 (free)
Dependency-Track5.1.0Self-hosted platform to store, track, and alert on SBOM data over timeApache 2.0 (free)
Docker or PodmanDocker 27.x / Podman 5.xRuns Dependency-Track and any containerized targets you scanN/A
Git2.40+Version control for the sample projectN/A
Node.js20 LTS or 22 LTSRuns the sample application used in this walkthroughN/A

You will also want a GitHub account if you plan to wire SBOM generation into CI/CD, and roughly 4GB of free RAM if you run Dependency-Track locally via Docker Compose. Everything here also works with GitLab CI, Jenkins, or CircleCI with minor syntax changes to the pipeline definition.

Step 1: Understand the two SBOM formats you will actually encounter

Almost every tool you touch will output one of two formats: CycloneDX or SPDX. Both are accepted under the EU Cyber Resilience Act’s Annex I Part II(1) guidance as “commonly used machine-readable formats.” Picking the wrong one for your downstream tooling is the single most common early mistake in SBOM adoption, so it is worth understanding the difference before generating anything.

CycloneDX, maintained by OWASP, is now at spec version 1.7 (ratified October 2025) and was purpose-built for application security use cases: vulnerability correlation, license compliance, and dependency graphs. A CycloneDX 2.0 revision is in progress with Ecma ratification expected around December 2026, extending the format beyond SBOMs into threat models and provenance attestations.

SPDX (Software Package Data Exchange) is an ISO-standardized format (ISO/IEC 5962:2021), maintained at spdx.dev and currently at version 3.0.1, that grew out of license-compliance tooling and is broader in scope, covering hardware and AI/ML model bills of materials in addition to software. If your organization needs to satisfy a legal or procurement requirement that explicitly cites SPDX, use SPDX. If you are optimizing for vulnerability scanning speed and tooling compatibility with Grype, Trivy, and Dependency-Track, CycloneDX (full specification maintained on GitHub) has the deeper ecosystem right now. This tutorial generates both so you can see the structural differences directly.

Step 2: Install Syft

Syft, built by Anchore and hosted at github.com/anchore/syft, is the closest thing the industry has to a default SBOM generator. It can scan a local directory, a Git repository, a running container, or an OCI image pulled straight from a registry. Install it with the official script:

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

# Verify installation
syft version

On macOS you can also install via Homebrew (brew install syft), and on Windows via Scoop (scoop install syft) or by downloading the release binary directly from the Syft GitHub releases page. The expected output from syft version looks like this:

Application:        syft
Version:            1.51.1
BuildDate:          2026-08-27T14:02:11Z
GitCommit:          a3f9c21
GitDescription:     v1.51.1
Platform:           linux/amd64
GoVersion:          go1.23.4
Compiler:           gc

Step 3: Generate your first SBOM from a directory

Clone or navigate to any Node.js, Python, Go, Java, or Rust project. For this tutorial we will use a small Express.js sample app. Run Syft against the project root:

git clone https://github.com/expressjs/express-generator-sample sbom-demo
cd sbom-demo
npm install

# Generate a CycloneDX SBOM
syft dir:. -o cyclonedx-json=sbom-cyclonedx.json

# Generate an SPDX SBOM from the same source
syft dir:. -o spdx-json=sbom-spdx.json

Syft walks the project, reads package-lock.json (or requirements.txt, go.sum, Cargo.lock, and so on depending on ecosystem), and resolves every direct and transitive dependency into a structured component list. On a mid-sized Node.js project with 150-200 dependencies, this typically completes in under 10 seconds. The terminal output during a scan looks like this:

 ✔ Indexed file system                                                      sbom-demo
 ✔ Cataloged contents                                     327 packages, 4 executables
   ├── ✔ Package cataloger: javascript-lock-cataloger    312 packages
   ├── ✔ Package cataloger: binary-cataloger                4 packages
   └── ✔ Package cataloger: file-metadata-cataloger        11 packages

Open sbom-cyclonedx.json and you will see a structured document with a components array. Each entry includes the package name, version, a PURL (package URL) identifier, and where available, a license string:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.7",
  "serialNumber": "urn:uuid:3f2504e0-4f89-11d3-9a0c-0305e82c3301",
  "version": 1,
  "components": [
    {
      "type": "library",
      "name": "express",
      "version": "4.21.2",
      "purl": "pkg:npm/[email protected]",
      "licenses": [{ "license": { "id": "MIT" } }]
    }
  ]
}

Step 4: Generate an SBOM from a container image

Source-level SBOMs miss anything baked into the container: the base OS packages, the language runtime itself, and any binaries installed via apt, apk, or yum during the build. To capture the full picture, point Syft at the built image instead of the source directory:

# Build the image first
docker build -t sbom-demo:latest .

# Generate an SBOM from the image
syft sbom-demo:latest -o cyclonedx-json=sbom-image-cyclonedx.json

# Or pull directly from a registry without a local build
syft registry:node:22-alpine -o cyclonedx-json=sbom-base-image.json

A container-level scan surfaces two to three times more components than a source-only scan on a typical Node or Python image, because it picks up the base OS’s package manager entries (Debian’s dpkg, Alpine’s apk) alongside your application dependencies. This is the SBOM you actually want in production, since it reflects what is running, not just what you wrote.

Step 5: Install Grype and scan the SBOM for known vulnerabilities

An SBOM by itself is just an inventory. Pair it with Grype, also from Anchore and hosted at github.com/anchore/grype, to cross-reference every component against known vulnerability databases (NVD, GitHub Security Advisories, and distro-specific feeds).

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

# Scan a previously generated SBOM instead of re-scanning the image
grype sbom:./sbom-image-cyclonedx.json -o table

Feeding Grype an existing SBOM instead of scanning the image directly is faster and lets you decouple “generate the inventory” from “check it against threat intel,” which matters once you are running this on every commit. Sample output:

NAME         INSTALLED  FIXED-IN  TYPE  VULNERABILITY        SEVERITY
libssl3      3.0.11-r0  3.0.16-r0 apk   CVE-2026-1234        High
express      4.21.0     4.21.2    npm   GHSA-rv95-896h-c2vc  Medium
busybox      1.36.0     1.36.1-r2 apk   CVE-2026-9981        Critical

3 vulnerabilities found: 1 Critical, 1 High, 1 Medium

Grype also supports a --fail-on flag, which is what makes it useful as a CI gate rather than just a reporting tool: grype sbom:./sbom-image-cyclonedx.json --fail-on critical will exit with a non-zero status code if any critical-severity CVE is present, breaking the build before a vulnerable image ships.

Step 6: Try Trivy as a single-tool alternative

Trivy, maintained by Aqua Security, folds SBOM generation and vulnerability scanning into a single binary, which some teams prefer over running Syft and Grype separately. It is currently at v0.74.0.

# Install Trivy (Linux)
sudo apt-get install trivy

# Generate an SBOM AND scan it in one command
trivy image --format cyclonedx --output trivy-sbom.json sbom-demo:latest
trivy sbom trivy-sbom.json --severity CRITICAL,HIGH

Trivy also scans infrastructure-as-code files (Terraform, Kubernetes manifests) and detects hardcoded secrets in the same pass, which Syft and Grype do not do. The tradeoff is that Trivy’s SBOM output is somewhat less detailed on transitive dependency relationships than Syft’s, so many teams run Syft for the SBOM itself and Trivy as a secondary secrets/misconfiguration check. Neither approach is wrong; pick based on whether you want one tool to learn or two tools each doing one job well.

Step 7: Stand up Dependency-Track to store SBOMs over time

A one-off SBOM answers “what is in this build right now.” The regulatory requirement, and the actual security value, comes from tracking how your dependency tree changes over time and getting alerted the moment a component you already shipped turns out to be vulnerable. Dependency-Track, now at version 5.1.0, is the open-source platform built for exactly that. Run it via Docker Compose:

mkdir dtrack && cd dtrack
curl -LO https://dependencytrack.org/docker-compose.yml
docker compose up -d

# Check that both services are healthy (takes 1-2 minutes on first boot)
docker compose ps

Once running, the UI is available at http://localhost:8080. The default login is admin / admin, and you will be forced to set a new password on first login. Dependency-Track 5.1 adds native ingestion for CycloneDX 1.7 and built-in tracking of Known Exploited Vulnerabilities (KEV), pulling directly from CISA’s KEV catalog so you can prioritize fixes for bugs that are being actively exploited in the wild, not just theoretically dangerous.

Step 8: Create a project and upload your SBOM

Inside the Dependency-Track UI, create a new project matching your application name and version. Then upload the CycloneDX file you generated in Step 3 or Step 4, either through the UI or via the API:

# Get an API key from Administration > Access Management > Teams
export DTRACK_API_KEY="odt_xxxxxxxxxxxxxxxxxxxxx"
export DTRACK_URL="http://localhost:8080"

curl -X POST "$DTRACK_URL/api/v1/bom" \
  -H "X-Api-Key: $DTRACK_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F "autoCreate=true" \
  -F "projectName=sbom-demo" \
  -F "projectVersion=1.0.0" \
  -F "[email protected]"

Within a minute or two, Dependency-Track will have processed the BOM, matched every component against its vulnerability database, and populated the project dashboard with a risk score, a license summary, and a list of any flagged CVEs. This is the view your security team should be checking weekly, not a spreadsheet someone updates by hand.

Step 9: Automate SBOM generation in GitHub Actions

Manual generation defeats the point. The CISA 2026 Minimum Elements explicitly call for automation support as one of the core requirements, and 74% of organizations surveyed in 2026 reported at least partially automating per-release SBOM generation. Here is a workflow that generates an SBOM on every push to main, scans it with Grype, and fails the build on critical vulnerabilities:

name: SBOM Generation and Scan

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  sbom:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

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

      - name: Install Grype
        run: curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin

      - name: Generate SBOM
        run: syft dir:. -o cyclonedx-json=sbom.json

      - name: Scan SBOM for critical vulnerabilities
        run: grype sbom:./sbom.json --fail-on critical

      - name: Upload SBOM to Dependency-Track
        run: |
          curl -X POST "${{ secrets.DTRACK_URL }}/api/v1/bom" \
            -H "X-Api-Key: ${{ secrets.DTRACK_API_KEY }}" \
            -F "autoCreate=true" \
            -F "projectName=${{ github.repository }}" \
            -F "projectVersion=${{ github.sha }}" \
            -F "[email protected]"

      - name: Archive SBOM artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.json

Store DTRACK_URL and DTRACK_API_KEY as encrypted repository secrets rather than hardcoding them. Archiving the SBOM as a build artifact, in addition to uploading it to Dependency-Track, gives you a durable per-build record that satisfies the CISA requirement to timestamp and retain SBOM data.

Step 10: Sign your SBOM to satisfy the 2026 CISA baseline

One of the genuinely new requirements in CISA’s 2026 Minimum Elements is an SBOM Author Signature, a cryptographic signature proving who generated the document and that it has not been tampered with since. The open-source project Cosign, part of the Sigstore ecosystem, is the most common way to add this without standing up your own PKI:

# Install cosign
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
chmod +x cosign-linux-amd64 && sudo mv cosign-linux-amd64 /usr/local/bin/cosign

# Generate a keypair (or use keyless signing with an OIDC identity in CI)
cosign generate-key-pair

# Sign the SBOM
cosign sign-blob --key cosign.key sbom.json --output-signature sbom.json.sig

# Anyone can later verify it came from you and was not modified
cosign verify-blob --key cosign.pub --signature sbom.json.sig sbom.json

In a CI environment, use Cosign’s keyless signing mode with your CI provider’s OIDC token instead of managing a long-lived private key. This avoids the single biggest operational headache with signing: key storage and rotation.

Step 11: Query your SBOMs when the next supply chain attack drops

This is the step that justifies everything above it. When a package like the compromised versions involved in the ChainDrop npm worm or the SleeperGem RubyGems campaign gets disclosed, the difference between an organization with SBOMs and one without is measured in hours versus days. With Dependency-Track, you can search the “Portfolio” view across every tracked project for a specific PURL:

# Search all tracked projects for a specific compromised package via API
curl -s "$DTRACK_URL/api/v1/component/identity?purl=pkg:npm/[email protected]" \
  -H "X-Api-Key: $DTRACK_API_KEY" | jq '.[] | {project: .project.name, version: .version}'

That single query tells you, across your entire application portfolio, exactly which services need an emergency patch, instead of paging every team and asking them to manually check their package-lock.json files. This is also the workflow security teams increasingly demand from vendors: if a supplier cannot answer “do you use this component” within the hour, that is now treated as a supply chain risk indicator in its own right.

Step 12: Set up alerting for newly disclosed vulnerabilities

SBOMs decay the moment you stop updating them, since new CVEs get disclosed against components you already shipped months ago. Configure Dependency-Track to notify your team automatically instead of relying on someone remembering to re-scan:

# In the Dependency-Track UI:
# Administration > Notifications > Create Alert
# Publisher: Slack (or Microsoft Teams, email, webhook)
# Notification scope: PORTFOLIO
# Trigger on: NEW_VULNERABILITY, NEW_VULNERABLE_DEPENDENCY
# Notification level: WARNING or higher

With this configured, the moment Dependency-Track’s vulnerability feed updates overnight and flags a component already in your portfolio, a message lands in your team’s Slack channel automatically, no manual re-scan required. Pair this with the KEV-tracking feature in Dependency-Track 5.1 to distinguish “theoretically vulnerable” from “actively being exploited right now,” which should drive very different response timelines.

Common pitfalls when generating and managing SBOMs

These are the mistakes that show up repeatedly once teams move past a single test SBOM and try to run this at scale.

  • Scanning source only, never the built artifact. A source-level SBOM misses base OS packages, runtime binaries, and anything installed during the Docker build. Always generate at least one SBOM from the final container image, not just the repository.
  • Picking a format your downstream tools cannot read. Verify that your vulnerability scanner, your compliance platform, and any customer-facing SBOM delivery requirement all agree on CycloneDX versus SPDX before you standardize. Switching formats after six months of pipeline history is painful.
  • Treating SBOM generation as a one-time compliance checkbox. A study of 2025-2026 supply chain incidents found that stale SBOMs, generated once at release and never refreshed, were functionally useless during actual incident response because the component list no longer matched what was deployed.
  • Only capturing direct dependencies. The CRA’s minimum bar is top-level dependencies, but the vast majority of real-world vulnerabilities in 2026 supply chain attacks were in transitive dependencies two or three levels deep. Configure Syft and Trivy to resolve the full dependency tree, not just what is declared in your manifest.
  • No signature or provenance attached. An unsigned SBOM is trivially easy to spoof or tamper with. If you skip Step 10, you technically have an SBOM but it fails the CISA 2026 baseline and provides weaker assurance to anyone consuming it.

SBOM tool comparison: open source versus commercial

Syft, Grype, and Trivy handle generation and scanning for free with no seat limits, which covers most engineering teams. Larger organizations often add a commercial platform on top for portfolio-wide dashboards, compliance reporting, and vendor SBOM ingestion. Here is how the current pricing landscape breaks down:

ToolTypeStarting priceBest for
Syft + GrypeOpen source$0Generation and scanning in CI/CD, unlimited use
TrivyOpen source$0Combined SBOM, secrets, and IaC scanning in one binary
Dependency-Track (self-hosted)Open source$0 (infrastructure cost only)Portfolio-wide tracking and alerting
SnykCommercialFree tier; Team plan from $25/developer/monthTeams wanting SBOM plus developer-friendly fix suggestions
FOSSACommercialFree tier (5 projects); Business from $20/project/monthLicense compliance alongside SBOM generation
Anchore EnterpriseCommercialList pricing around $34,500/year for a single-host deploymentLarge enterprises needing policy enforcement at scale
JFrog XrayCommercial (bundled)Included in JFrog Platform Pro X, from roughly $150/monthOrganizations already standardized on JFrog Artifactory

Troubleshooting common SBOM generation issues

Here are the errors and confusing outputs you are most likely to run into, and how to resolve each one.

  • Syft reports zero components on a Node.js project. This almost always means Syft could not find a lockfile. Run npm install or npm ci first to generate package-lock.json, since Syft parses the lockfile rather than package.json alone to get resolved, exact versions.
  • Grype scan hangs or times out on first run. Grype downloads and caches a local vulnerability database (several hundred MB) on first execution. Run grype db update manually first if you are on a slow connection, and check grype db status to confirm the database downloaded successfully.
  • Dependency-Track shows “BOM_PROCESSING_FAILED” after upload. This typically means the CycloneDX file is malformed or references a spec version Dependency-Track does not yet support. Validate the file first with cyclonedx-cli validate --input-file sbom.json before uploading.
  • Container image SBOM is missing expected OS packages. If you built a multi-stage Docker image, make sure you are scanning the final stage, not an intermediate build stage. Syft can only see what is present in the layer you point it at.
  • Vulnerability counts differ wildly between Grype and Trivy on the same image. The two tools pull from overlapping but not identical vulnerability databases and apply different severity-scoring logic. This is expected; many teams run both and treat any CVE flagged by either tool as worth investigating rather than trying to reconcile the exact counts.
  • Cosign signature verification fails after signing. Confirm you are verifying against the matching public key (cosign.pub) generated alongside the private key used to sign, and that the SBOM file has not been re-formatted or had whitespace changed after signing, which invalidates the signature.
  • GitHub Actions workflow fails on the Grype fail-on step even with no critical CVEs visible. Check for CVEs in transitive dependencies that do not show in a shallow scan; run grype sbom:./sbom.json -o json | jq '.matches[].vulnerability.severity' to see the full raw match list Grype used to make its decision.
  • Dependency-Track alerts are not firing despite new CVEs appearing in the dashboard. Double-check the notification rule’s scope is set to PORTFOLIO rather than a single project, and confirm the publisher (Slack, Teams, webhook) credentials have not expired.

Advanced tips for scaling SBOM management

Once the basic pipeline is running, a few refinements separate teams that treat SBOMs as a real security control from teams that generate them purely to check a compliance box.

First, generate SBOMs at multiple points in the pipeline, not just at final release. A source-level SBOM at pull-request time catches a newly introduced vulnerable dependency before merge; a container-level SBOM at deploy time captures what is actually running. Comparing the two over time also reveals dependency drift, cases where a transitive dependency silently upgraded between builds without anyone noticing.

Second, integrate SBOM data with your incident response runbook explicitly, not as an afterthought. When your security team receives a new critical CVE alert, the runbook should say “query Dependency-Track for this PURL across all projects” as an explicit first step, not something someone has to remember to do under pressure.

Third, if you distribute software to customers or government buyers, build an automated process to generate a customer-facing SBOM export on every release, formatted to the specific minimum elements your buyer requires. Manually preparing SBOM deliverables for each customer request does not scale past a handful of enterprise contracts.

Fourth, watch the CycloneDX 2.0 transition closing out 2026. It extends the format beyond a static component list into threat models, controls, and provenance attestations, which means the SBOM tooling landscape is likely to shift again within the next 12 months. Building your pipeline around Syft and Grype’s standard CLI flags rather than deeply custom scripting will make that migration far less painful when it lands.

SBOMs beyond application code: AI models and hardware

SBOMs started as a way to inventory application dependencies, but the scope is widening fast. SPDX 3.0 explicitly added support for AI and machine learning bills of materials (sometimes shortened to AIBOM), covering training data provenance, model weights, and fine-tuning lineage rather than just code packages. If your team ships a product that bundles a third-party model or fine-tunes an open-weight base model, treating that model the same way you treat an npm dependency, tracked, versioned, and scanned for known issues, is quickly becoming an expectation rather than an edge case. The same logic extends to hardware: a growing number of CRA-adjacent guidance documents ask device manufacturers to maintain a hardware bill of materials alongside the software one, since a vulnerable firmware component buried in a purchased hardware module is functionally the same supply chain risk as a vulnerable open-source library.

None of this changes the workflow covered in this tutorial in a fundamental way. Syft and the CycloneDX and SPDX formats are both extending their existing schemas to cover these new component types rather than requiring a separate toolchain, which is exactly the kind of format stability that makes standardizing on CycloneDX or SPDX now, rather than a proprietary in-house format, worth the short-term setup cost.

Complete working project: SBOM pipeline from clone to alert

Putting every step together, here is the full sequence for a working end-to-end SBOM pipeline you can run today, from a fresh clone through automated alerting:

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

# 2. Stand up Dependency-Track
mkdir dtrack && cd dtrack
curl -LO https://dependencytrack.org/docker-compose.yml
docker compose up -d
sleep 90  # first boot takes a minute or two

# 3. Build your application image
cd ../sbom-demo
docker build -t sbom-demo:latest .

# 4. Generate the SBOM from the built image
syft sbom-demo:latest -o cyclonedx-json=sbom.json

# 5. Scan locally and fail fast on critical issues
grype sbom:./sbom.json --fail-on critical

# 6. Sign it
cosign sign-blob --key cosign.key sbom.json --output-signature sbom.json.sig

# 7. Upload to Dependency-Track for ongoing tracking
curl -X POST "http://localhost:8080/api/v1/bom" \
  -H "X-Api-Key: $DTRACK_API_KEY" \
  -F "autoCreate=true" \
  -F "projectName=sbom-demo" \
  -F "projectVersion=1.0.0" \
  -F "[email protected]"

echo "Pipeline complete. Check http://localhost:8080 for the risk dashboard."

Wrap steps 3 through 7 into your CI/CD pipeline using the GitHub Actions example from Step 9, and you have a self-sustaining system: every commit produces a signed, tracked SBOM, every newly disclosed CVE against a component you use triggers a Slack alert, and every audit or customer request for an SBOM can be answered by pulling the latest artifact rather than starting from scratch.

Frequently asked questions

Do I need an SBOM if I am not selling to the US federal government or the EU?
Not legally, yet, for most private-sector companies outside those markets. But the incentive to have one is independent of regulation: an SBOM cuts incident response time for supply chain attacks from days to minutes, and an increasing number of enterprise customers now require a current SBOM as part of vendor security questionnaires regardless of where they operate.

Which format should I standardize on, CycloneDX or SPDX?
CycloneDX has the stronger ecosystem for vulnerability scanning and is the default output for Syft, Grype, Trivy, and Dependency-Track. Use SPDX only if a specific legal, procurement, or customer requirement explicitly demands it.

Can I generate an SBOM without Docker?
Yes. Syft’s dir: mode scans a source directory directly with no container involved, which is sufficient for source-level dependency tracking. You only need a container when you want to capture what is baked into the final runtime image, including base OS packages.

How often should I regenerate an SBOM?
On every build that reaches a shared branch or gets deployed, at minimum. A CISA-aligned baseline expects SBOMs to be kept current throughout the product’s life cycle, which in practice means wiring generation into CI/CD rather than running it manually on a schedule.

Does an SBOM replace vulnerability scanning?
No. An SBOM is the inventory; a scanner like Grype or Trivy is what cross-references that inventory against known vulnerabilities. You need both, and ideally the SBOM should be reusable across multiple scanning and compliance tools rather than regenerated separately for each one.

What is the difference between Grype and Trivy if they both scan for vulnerabilities?
Grype is purpose-built as a vulnerability scanner that consumes SBOMs (its own or third-party) and focuses narrowly on that job. Trivy is broader, combining SBOM generation, vulnerability scanning, secrets detection, and infrastructure-as-code misconfiguration scanning in one tool. Many teams run both since their vulnerability databases do not perfectly overlap.

Is Dependency-Track required, or can I just store SBOM files in a folder?
You can store raw files, but you lose the ability to query across your entire portfolio when a new vulnerability drops, and you lose automated alerting. For a single small project, files on disk are workable. For any organization tracking more than a handful of applications, a platform like Dependency-Track pays for itself the first time you need to answer “are we affected by this” across dozens of services at once.

What happens if my SBOM is incomplete or inaccurate?
Under the EU Cyber Resilience Act, manufacturers are required to keep SBOMs accurate and current as part of their vulnerability handling obligations; a stale or incomplete SBOM undermines the compliance value entirely and, more practically, gives your own security team false confidence during an actual incident. Treat SBOM accuracy as a build-quality gate, not a documentation afterthought.

Related Coverage

Sofia Lindström

Sofia Lindström

Editor-in-Chief

Sofia Lindström is the Editor-in-Chief at Tech Insider, where she leads editorial strategy and oversees coverage across AI, cybersecurity, and enterprise technology. With over a decade in Swedish tech journalism, she previously served as technology editor at Dagens Industri and covered the Nordic startup ecosystem for Breakit. Sofia holds an MSc in Media Technology from KTH Royal Institute of Technology and is a frequent speaker at Web Summit and Slush. She is passionate about making complex technology accessible to business leaders.

View all articles