Guide 132 worked guide

How to read an SBOM and find the components that matter

Read an SBOM through artifact identity, component occurrences, dependency edges, and completeness, then turn missing inventory facts into precise follow-up requests.

Start an SBOM review by asking what exact product or release this inventory describes, how it was generated, and whether its component and dependency records are complete enough for your decision. Then locate the package by ecosystem, name and version; follow its direct or transitive path to the application; and compare it with a current advisory. The result is a candidate for further investigation, not a verdict that an attacker can use the flaw. If the SBOM was made from a source checkout while the question concerns a production image, first establish the source-to-image link or obtain an artifact-level inventory.

An SBOM is a structured inventory, not a penetration test. The CycloneDX specification can represent components, dependency relationships, provenance, services and completeness information. The NTIA minimum-elements report describes the baseline data and practices needed to make an SBOM useful. Neither standard makes an incomplete or stale inventory complete by itself.

Read the envelope before the package list

When handed a file called sbom.json, do not begin with a text search for a CVE. Inspect five outer facts first:

  1. Format and version. A CycloneDX, SPDX or other SBOM has its own schema and relationship rules. This example is pinned to CycloneDX 1.7. Read an actual file against its declared specification version, using the specification overview to locate that version.
  2. Subject. Find the metadata component or equivalent target: application, library, container image or release. “Harbor Billing” without a version, revision or artifact digest is an ambiguous target.
  3. Creation context. Note the tool, time, inputs and lifecycle point when provided. An SBOM generated before a production packaging step may miss components introduced afterward; a post-build image SBOM may omit build-only packages.
  4. Identity and completeness. Record the SBOM's own identifier and whether the producer states that components, dependency edges or sections are incomplete. CycloneDX has composition information for describing completeness; absence of such a statement is not proof of completeness.
  5. Trust path. Ask who supplied the file and how it was tied to the artifact. A downloaded SBOM with no release binding is useful for search but weak as evidence about production.

Only then scan the components. A version-less entry may identify a project but cannot be matched precisely to an affected version range. A package name without an ecosystem can collide with another registry. Package-URL uses an ecosystem type, namespace, name and optional version to make component identity more precise. A PURL still needs to be checked against the advisory's naming conventions and the actual artifact.

Work through a small, fictional CycloneDX file

Illustrative case: Harbor Billing's security engineer receives a simplified CycloneDX SBOM for release 2026.10.18. All package names, versions, identifiers and the advisory below are invented. The example omits many valid CycloneDX fields so the relationships are visible; it is not a claim about a real software product.

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.7",
  "serialNumber": "urn:uuid:11111111-2222-4333-8444-555555555555",
  "version": 1,
  "metadata": {
    "component": {
      "type": "application",
      "bom-ref": "app:harbor-billing",
      "name": "harbor-billing",
      "version": "2026.10.18"
    }
  },
  "components": [
    {
      "type": "library",
      "bom-ref": "pkg:npm/%40harbor-demo/report-kit@5.0.0",
      "name": "@harbor-demo/report-kit",
      "version": "5.0.0",
      "purl": "pkg:npm/%40harbor-demo/report-kit@5.0.0"
    },
    {
      "type": "library",
      "bom-ref": "pkg:npm/%40harbor-demo/archive-reader@2.1.0",
      "name": "@harbor-demo/archive-reader",
      "version": "2.1.0",
      "purl": "pkg:npm/%40harbor-demo/archive-reader@2.1.0"
    }
  ],
  "dependencies": [
    {
      "ref": "app:harbor-billing",
      "dependsOn": ["pkg:npm/%40harbor-demo/report-kit@5.0.0"]
    },
    {
      "ref": "pkg:npm/%40harbor-demo/report-kit@5.0.0",
      "dependsOn": ["pkg:npm/%40harbor-demo/archive-reader@2.1.0"]
    }
  ]
}

The metadata says the subject is the application release. It does not say which production image or region contains it. The two component entries identify versions. The dependencies section says the application depends directly on report-kit, which in turn depends on archive-reader. That makes archive-reader a transitive dependency. The CycloneDX SBOM guide explains that bom-ref connects component records to graph edges; an omitted edge or missing referenced component limits the graph's usefulness. Here archive-reader has no dependency record of its own: its downstream dependencies are unknown, not necessarily empty. An explicitly dependency-free leaf would need its own record with an empty dependsOn list under the 1.7 schema.

Suppose an invented DEMO-ADV-01 says archive-reader versions before 2.1.1 contain a path traversal flaw when a particular extraction mode receives attacker-controlled archive entries. 2.1.0 is inside that fictional range. The match proves only that the SBOM names a potentially affected component. It does not show that the vulnerable extraction mode is called, that customer input reaches it, or that this SBOM describes the deployed artifact. A security engineer who skips those steps may create a misleading “critical production vulnerability” ticket.

Turn the file into a review worksheet

Use a worksheet like this to capture both what the SBOM provides and what it cannot:

Question Harbor answer from this SBOM Evidence still needed
What is the subject? harbor-billing 2026.10.18 application. Build provenance linking release to immutable artifact digest and deployment.
Which component matches? npm @harbor-demo/archive-reader 2.1.0. Confirm advisory ecosystem, affected range and whether a fork/backport changes applicability.
How did it enter? Through @harbor-demo/report-kit 5.0.0. Confirm the graph matches the actual resolved tree.
Is it direct or transitive? Transitive in this graph. Check whether other parents pull another copy or version.
Is the graph complete? Not stated in the simplified file. Producer's completeness declaration, tool scope, exclusions and generation log.
Does the vulnerable operation run? Not answerable from these entries. Caller/configuration review and, if needed, authorized validation.
Is the application affected? Under investigation. Deployed-artifact match, vulnerable-path evidence and relevant controls.

The OSV schema separates affected packages, versions and ranges; use the advisory's own record to evaluate the version, not a guessed cutoff based on a scanner badge. If a vendor supplies a VEX document, check that its product identity and release actually match Harbor and that a “not affected” rationale covers the same build and vulnerable behavior. A VEX status for an upstream product does not automatically settle your application status.

Reconcile a second SBOM instead of choosing the newer file

A second synthetic inventory arrives. It describes finished image M42, whereas the first file describes the application release before packaging. Its entries contain two copies of the archive reader and one incomplete reference:

Inventory record Identity Parent evidence Interpretation
reader-fixed npm @harbor-demo/archive-reader@2.1.1 report-kit@5.0.1 points to this reference Fixed copy under the updated parent
reader-legacy npm @harbor-demo/archive-reader@2.1.0 Copied legacy-export bundle points to this reference Affected copy remains in finished image
reader-unknown Unresolved reference; package identity unavailable An edge names this reference but no corresponding component is supplied Unresolved graph/identity defect; cannot classify

The first file was not necessarily wrong. Packaging added the legacy bundle afterward. The second file is more relevant to the shipped image, but its malformed or incomplete graph still needs repair. A successful JSON parse is not proof that all references resolve or that the producer inventoried every location.

The analyst's normalization sheet therefore keeps copy identity and artifact subject alongside package identity. It does not deduplicate by name and keep only 2.1.1. For each row, preserve the producer's reference, ecosystem, full name, version, artifact subject, location when available, and incoming dependency edges. Resolve every edge target to its component or explicitly record why it is external/unknown under the format's rules. The CycloneDX 1.7 schema defines the component and dependency structures; schema conformity and semantic inventory completeness remain different checks.

The completed disposition is:

M42's supplied inventory contains both fixed and affected npm archive-reader copies. The source-release inventory alone omitted the later copied legacy bundle. Do not close the advisory based on the fixed copy. Ask the build owner to identify and repair the legacy bundle and the incomplete reference; ask platform to map M42 to running workloads. Application exploitability remains a separate path assessment.

That note changes the work. The developer should update the copied bundle's origin or remove it, not repeatedly upgrade the already fixed direct parent. The producer should regenerate the inventory at the correct lifecycle point and repair the unresolved reference. A later clean file closes the inventory defect only when it describes the same intended artifact and explains the missing copy.

A vendor VEX statement could still help with the affected copy, but it must name the applicable product/build and rationale. “Not affected” for report-kit does not automatically cover the legacy bundle. This is the distinction an SBOM reader should be able to defend: inventory tells you which candidate to investigate and how it entered; application evidence decides what that candidate means.

Turn an incomplete inventory into a bounded request

For Harbor's second image, “please send a better SBOM” is too vague. The build owner needs three questions: which location contains the legacy bundle, what process copied it into M42, and what component the unresolved reference was intended to identify. Each answer repairs a different part of the inventory. A new file with the same missing edge does not answer any of them.

Keep the supplied inventory unchanged as evidence and attach the clarification separately. If the owner generates a replacement, identify its subject again and record which earlier document it supersedes. A newer timestamp alone does not establish that the replacement describes the same artifact. If the owner rebuilt the image while repairing the inventory process, the resulting SBOM describes a new subject; retain the earlier image's unresolved assessment rather than silently moving the question to the cleaner build.

The reader can still take useful action before every row is complete. The known affected copy in the legacy bundle supports a repair investigation for that copy. The known fixed copy supports a limited conclusion about its own location. The unresolved reference prevents a complete component inventory conclusion, but it does not invalidate evidence already established for the identified components. Write these outcomes separately so that one uncertainty neither disappears nor freezes unrelated work.

Preserve component identity in the downstream ticket

Suppose a dependency ticketing system accepts only a package name and version. Exporting both archive-reader copies into that shape can lose the difference between the normal application dependency and the copied bundle. The ticket then risks closing when the normal dependency is updated even though the bundle remains.

Include the artifact subject and a stable reference to the component occurrence in the evidence attachment. If the receiving tool cannot retain these distinctions in its own fields, describe them explicitly in the ticket and keep the inventory as the authoritative detail. The owner should be able to identify which bytes or build input the repair must change without reconstructing the entire investigation.

For this example, closure requires evidence about the legacy bundle's replacement or removal and the final artifact that contains it. A fresh inventory can confirm the resulting component record, while deployment evidence answers where that artifact runs. The SBOM reader's job is to make those next questions precise, including what the document cannot establish by itself.

Next action: take one SBOM from a recent release and fill the worksheet before importing its alerts into a fix queue. To establish whether its package is actually running, continue with how to check whether a vulnerable package is deployed. To turn the resulting exposure into a work order, use dependency vulnerability prioritization.