L5 · Non-functional depth
L5Go deeper5 min read

Supply chain: SBOM and dependency risk

Most of what you ship was written by strangers. Knowing what is actually in the build, where it came from, and how fast you could replace a compromised package is now a mainstream quality concern rather than a niche one.

Modern applications are mostly other people's code. A typical service pulls in hundreds of transitive dependencies, and most teams cannot name half of them off the top of their head. Supply chain security asks a simple question before every release: do you actually know what is running in production?

This guide covers what a Software Bill of Materials is, why it matters after a string of real attacks, and which tools produce and check one. It also covers where a QA engineer fits into verifying it, alongside checks like API schema validation.

What an SBOM actually is

A Software Bill of Materials is a structured inventory of every component that makes up a piece of software. It lists direct dependencies, transitive dependencies, their versions, licenses, and known identifiers. Think of it as an ingredient list for your build artifact rather than a marketing description of it.

Two formats dominate. SPDX, originated by the Linux Foundation, focuses heavily on license compliance and is now an ISO standard. CycloneDX, from OWASP, was built specifically for security use cases. It carries richer vulnerability and dependency-graph data.

Most tooling today can emit either format, and many pipelines generate both. Different downstream consumers expect different formats: a legal team wants SPDX for license review, while a security scanner wants CycloneDX for vulnerability matching.

An SBOM is not a one-time document. It should be regenerated on every build, because a dependency bump, a transitive upgrade, or a new package pulled in by a teammate all change what is actually shipping.

Why this became urgent

Supply chain risk is not theoretical. A handful of incidents changed how seriously teams treat it.

  • event-stream (2018): a popular npm package changed hands to a new maintainer who quietly added a malicious dependency targeting a specific cryptocurrency wallet app. Millions of installs pulled it in before anyone noticed.
  • xz-utils (2024): a multi-year social engineering effort placed a backdoor inside a core compression library used by most Linux distributions. It reached into SSH authentication. It was caught by chance, not by process.
  • Log4Shell (2021): a remote code execution flaw hit Log4j, a logging library buried three or four levels deep in countless Java applications. It forced emergency patching across the industry, because almost nobody had an inventory of where the library actually lived.

The common thread is transitive risk. You did not choose the vulnerable component directly. Someone you trusted did, and you had no visibility into it until it was already a headline.

A worked example. Say your team ships a Java service that pulls in Log4j through a third-party auth library, four layers deep in the dependency tree. When Log4Shell breaks, your security team asks every team: are you affected?

Without an SBOM, someone has to manually walk the dependency tree of every deployed service. That process can take days across a large org. With an SBOM already generated for each build and stored in Dependency-Track, the same question becomes a single query. Search for the component name, and every affected build lists itself in minutes.

Tools that generate and scan SBOMs

A handful of open source tools cover most of what a team needs, and they compose well in a pipeline.

  • Syft (Anchore) scans a container image, filesystem, or archive and emits an SBOM in SPDX or CycloneDX format. It is the most common way to generate one as part of a build.
  • Grype (Anchore) consumes an SBOM or scans an image directly and matches components against known vulnerability databases, flagging affected versions with severity ratings.
  • Dependency-Track (OWASP) is a continuous monitoring platform. You feed it SBOMs over time, and it tracks new vulnerabilities disclosed against components you already shipped, even for builds from months ago.

A typical pipeline step looks like this:

ci-sbom-scan.sh
# Generate an SBOM for the built image
syft packages docker:myapp:latest -o cyclonedx-json > sbom.json

# Fail the build on high or critical vulnerabilities
grype sbom:sbom.json --fail-on high

# Upload for continuous tracking
curl -X POST "$DTRACK_URL/api/v1/bom" \
  -H "X-Api-Key: $DTRACK_API_KEY" \
  -F "project=$DTRACK_PROJECT_UUID" \
  -F "[email protected]"

Where QA fits in

QA is not usually the team writing the scanning scripts. But verifying supply chain integrity belongs in the release checklist, alongside functional and regression coverage. A few concrete responsibilities:

  • Confirm an SBOM was actually generated for the build under test, not a stale one from a previous release.
  • Treat a failed dependency scan as a release blocker with the same weight as a failed test suite, not an optional advisory.
  • Spot-check that flagged vulnerabilities are triaged, not silently suppressed or ignored because the scan is noisy.
  • Verify that the artifact being tested matches the artifact whose SBOM was scanned. A mismatch here quietly defeats the whole process.

This fits naturally next to the automated gates already covering CI/CD pipelines for test suites. A dependency scan is one more required check, alongside linting and test runs, before a build is allowed to merge or deploy. It also pairs with catching flaky tests, since a noisy scan that nobody trusts gets ignored the same way a flaky suite does.

Questions people ask

Is an SBOM the same as a vulnerability scan?

No. An SBOM is an inventory of what is in your build. A vulnerability scan, done by a tool like Grype, compares that inventory against known vulnerability databases. You need the inventory first before you can scan it meaningfully.

Do we need both SPDX and CycloneDX?

Not always. CycloneDX is generally preferred for security tooling because of its richer vulnerability data model, while SPDX is stronger for license compliance reporting. Many teams generate CycloneDX by default and add SPDX only if a customer or regulation requires it.

How often should an SBOM be regenerated?

On every build that ships to production. A dependency graph changes with every version bump, so an SBOM from last month tells you nothing reliable about today's artifact.