SBOM Generation as a Required CI Pipeline Stage
Regulators now require SBOMs built into CI pipelines, not generated after the fact.

The regulatory pressure driving SBOM adoption is no longer abstract or pending. It's current, specific, and consequential enough to change procurement outcomes and market access.
In the United States, Executive Order 14028 established SBOMs as a condition of selling software to the federal government. The FDA recommends SBOM submissions for medical devices. NIST SP 800-161r1 calls for SBOM generation on first consumption of every open-source version used, a posture that implies build-time generation rather than periodic audits. CISA's August 2025 draft guidance updates the 2021 NTIA baseline with four new required fields — Component Hash, License, Tool Name, and Generation Context. That last field is the telling one. Regulators don't only ask what components are present anymore; they're asking when and how the inventory was produced. A required field called "Generation Context" is, structurally, an argument against post-hoc generation.
The EU Cyber Resilience Act raises the stakes further. Article 14 reporting obligations, active since September 11, 2026, require that actively exploited vulnerabilities be reported within 24 hours and followed up within 14 days. The formal SBOM mandate arrives December 11, 2027, but organizations waiting until then will find the timeline unworkable. Non-compliance carries fines of up to €15 million or 2.5% of global annual turnover, and market surveillance authorities hold the power to pull products from EU markets entirely. BSI TR-03183-2 v2.1.0, published August 2025, fills the CRA's format and content gaps with concrete technical requirements. It's non-binding in formal terms, but it functions as the de facto technical benchmark while harmonized CEN/CENELEC standards remain pending.
In September 2025, CISA and NSA published joint guidance co-signed by 19 international partner agencies. That document frames automated SBOM generation, management, and consumption as a structural prerequisite for meaningful adoption, not a recommendation to be weighed against competing priorities.
The common thread across every mandate is this — the accuracy requirements, specific fields, machine-processable formats, cryptographic linkage between SBOM and artifact, can't be satisfied by manual or post-hoc processes. Read together, the regulations constitute a technical specification for build-time generation.
What a CI-embedded SBOM stage must actually produce
The minimum viable output of an SBOM pipeline stage is not a file. It's a file with specific, verifiable properties. That distinction matters because a file without those properties will pass a checkbox review and fail an incident response.
The SBOM must capture the resolved dependency graph, not declared dependencies. A manifest or lockfile describes what a developer intended to use. The resolved graph describes what the package manager actually fetched and linked, including the full transitive tree with exact pinned versions. These two things frequently diverge, and they diverge most dramatically in complex polyglot projects with nested dependency requirements. The divergence isn't exotic; it's the default.
Each component must carry a cryptographic hash, now a CISA 2025 required field, providing an immutable identifier independent of name and version strings. License information must accompany each component. Tool name and generation context, also now required, establish the provenance of the SBOM itself — which tool ran, against which artifact, at which stage of the build. A build number or commit SHA embedded in the SBOM ties it to a specific, reproducible moment rather than a floating version label.
Format choice is not neutral. CycloneDX is designed for security practitioners; it handles vulnerability metadata, VEX statements, AI-attribution tags, and cryptographic signatures natively, making it the appropriate choice for EU CRA and FedRAMP compliance contexts. SPDX is the native output format for Docker BuildKit attestations and is the lower-friction option when working primarily with OCI container toolchains. These two formats serve different evidence consumers. Teams with heterogeneous artifact types may need both.
Signing is not optional. A cosign attestation binds the SBOM cryptographically to a specific image digest, closing the provenance loop for SLSA and EO 14028 requirements. An unsigned SBOM can't prove it corresponds to the artifact it purports to describe. That's not a theoretical concern; it's a verification gap that a determined auditor can exploit during an incident, when the stakes for getting it wrong are highest.
VEX pairing deserves particular attention. An SBOM delivered without Vulnerability Exploitability Exchange statements forces security teams to re-triage the same "affected but not exploitable" findings on every subsequent scan cycle. I've watched this play out — the triage queue fills with known non-issues, analysts grow frustrated, and eventually someone with authority over the program starts asking whether they can reduce generation frequency. The problem isn't the generation. The problem is the missing VEX context that would have closed those findings the first time.
Storage requirements must be set with future CVE disclosures in mind. SBOMs must be keyed by artifact digest and version, retained well beyond standard pipeline artifact expiry windows, and stored in a system that supports structured queries. A 30-day artifact retention policy renders the SBOM useless for any vulnerability disclosed next quarter against a component present in today's build.
Where in the pipeline to place generation and why the position matters
The governing rule is straightforward: generate immediately after the final artifact is produced, not before, and not from source manifests alone. Everything else follows from that.
In container image pipelines, generation must target the final build stage only. Intermediate stages contain build tools, test frameworks, compiler toolchains, and development dependencies that don't ship to production. Including them inflates the SBOM with non-deployed components and creates false positives in every downstream vulnerability scan. Each false positive erodes team trust, which is a more serious operational risk than it sounds. BuildKit attestation flags applied to the final stage are the most reliable approach for OCI images because they operate on the same artifact manifest that will be pushed and deployed.
In application dependency pipelines, language-specific generator plugins produce materially higher-quality output than generic scanners because they run inside the build tool's own dependency resolution context. A CycloneDX plugin for Maven or Gradle reads the resolved graph as Maven or Gradle actually computed it, not an approximation derived from parsing the lockfile surface. Generating from the manifest rather than from within the build tool's resolution pass means missing transitive dependencies and the exact versions actually resolved. The difference in completeness is not marginal.
Larger teams benefit from a dual-phase approach. A preliminary SBOM generated during development builds provides fast feedback and surfaces new dependency introductions early, before they accumulate. A full, signed, attested SBOM generated during production deployment builds serves as the authoritative artifact for compliance evidence and incident response. These two phases serve different audiences and different purposes; conflating them into a single artifact usually means optimizing for neither.
Monorepo and multi-service architectures require per-deployable-artifact generation, not a single SBOM representing the entire repository. Impact analysis after a CVE disclosure must map to units that can actually be deployed or rolled back independently. A repository-level SBOM can't support that kind of operationally actionable analysis.
Generation failures must fail the build. Allowing the pipeline to continue after a generation error ships an artifact with no provenance record. The pipeline should apply the same zero-tolerance posture it applies to a failed unit test. Consistency in enforcement is what makes the program structurally reliable rather than aspirationally reliable.
The tooling choices that determine how much of the dependency tree you actually see
No single tool sees the complete picture, and the evidence for this is not anecdotal. For the same container image, Dependency-Track has found meaningfully more vulnerabilities in a Syft-generated SBOM than in a Trivy-generated one, partly because Syft's output includes the CPEs required to match against the NVD vulnerability database. This is not a quality defect in Trivy. It reflects a design difference — Trivy optimizes for integrated scanning speed; Syft optimizes for SBOM completeness. The practical implication is a paired approach, a build-system-native generator for application dependencies plus a container scanner for OS packages, covering evidence that either tool alone would miss.
Syft produces CPE-enriched SBOMs with strong CycloneDX and SPDX output and broad ecosystem coverage. Trivy integrates vulnerability scanning in the same pass, which suits teams that want generation and scanning as a single pipeline step without additional tooling overhead. cdxgen is CycloneDX-native, handles polyglot repositories well, and has a realistic one-sprint rollout timeline for teams starting from zero. Flox takes a different architectural position — rather than scanning artifacts after the fact, it generates a signed, hash-pinned SBOM directly from the reproducible environment's dependency graph, making SBOM output a near-free byproduct of environment definition rather than a separate instrumentation effort. Language-ecosystem plugins, CycloneDX for Maven and Gradle, the npm and yarn equivalents for Node, remain the highest-fidelity choice for application dependency graphs because they execute inside the build tool's own resolution context.
OS package coverage is not optional for container SBOMs. Base image vulnerabilities represent a primary attack surface, and application-layer scanning alone leaves them invisible. Docker Hardened Images, released in December 2025 and covering over 1,000 images under the Apache 2.0 license, ship with complete SBOMs, SLSA Build Level 3 provenance, and OpenVEX already attached. For teams using these images, base-layer SBOM generation is handled upstream, which meaningfully reduces the surface area that CI-level tooling must cover.
Reachability analysis is increasingly important for managing signal-to-noise ratios at scale. OSV-Scanner v2, released by Google in March 2025, determines whether a vulnerable code path is actually reachable in Go and Rust, reducing false-positive volume before findings reach developer queues. This doesn't replace SBOM completeness, but it makes continuous generation politically sustainable by preventing triage burden from compounding over time.
For management and consumption, OWASP Dependency-Track is open-source, CycloneDX-native, and supports continuous policy evaluation against stored SBOMs. GUAC, from OpenSSF, aggregates SBOMs, provenance attestations, and vulnerability reports into a queryable graph suited for organizations correlating evidence across multiple pipelines and artifact stores.
One risk that is frequently underestimated — generation tools run with elevated access to source code, dependency trees, and build artifacts. A compromised generator can exfiltrate or silently modify what it scans. Pin all generation tooling to immutable references, commit SHAs rather than version tags, verify checksums, and run generation in CI rather than on developer machines.
Why a reproducible build environment is a prerequisite for a trustworthy SBOM
Every tooling recommendation and pipeline placement decision in the previous sections rests on an assumption worth naming explicitly — the build environment is consistent, version-controlled, and produces the same outputs from the same inputs. Without that foundation, the SBOM is accurate relative to one build and approximate relative to every other.
The Reproducible Builds project documents the specific variables that affect build outputs — tool versions, operating system assumptions, file paths, locales, and time zones, among others. The problem is rarely dramatic. It's quiet and cumulative. The same setup instructions, executed on a developer laptop, in a CI runner, and on an automated build agent, can resolve to materially different tool versions if those environments are maintained independently, on different schedules, by different teams. The result is three different builds producing three different SBOMs, none of which is definitively authoritative. This situation describes the default configuration of most engineering organizations that haven't explicitly standardized their build environments. It's not a failure of intention; it's the natural entropy of independently maintained systems.
Reproducibility requires dependencies pinned to immutable versions or content-addressed digests rather than floating version ranges. Environment definitions must live in version control rather than be assembled through manual steps or accumulated hotfixes. Clean rebuilds should be tested on a defined schedule to surface drift before it compounds. And critically, a single environment definition should be used by developers, CI, and any automated agents, rather than three roughly-similar configurations that diverge silently over time.
Flox, as noted in the tooling discussion, occupies a particularly relevant position here. Because it generates a signed, hash-pinned SBOM from the environment's dependency graph rather than inferring one from build artifacts, the SBOM is a direct expression of a version-controlled, reproducible environment definition. That alignment between environment and inventory is precisely what the CISA 2025 "Generation Context" field is asking organizations to demonstrate.
When the environment is reproducible, the SBOM is reproducible. Any stakeholder can reconstruct the same inventory from the same version-controlled inputs. That property is what separates a snapshot from a verifiable record.
Common implementation mistakes that produce compliant-looking but inaccurate SBOMs
These mistakes are common not because they reflect carelessness but because they're the natural output of treating SBOM generation as a compliance task rather than a build engineering task. Each produces a document that satisfies a surface review and fails when it matters.
Generating from the manifest, not the build. Reading declared dependencies captures what the developer intended to include. It misses the transitive dependency tree and the exact versions actually resolved. The resulting SBOM describes intent, not reality. This mistake is particularly insidious because the output looks complete; there's no obvious signal that anything is missing.
Ignoring OS packages in container SBOMs. Application-layer scanning alone leaves base image vulnerabilities invisible. A substantial share of container CVE exposure lives in the OS layer. An SBOM that omits it produces a false sense of completeness, which is worse than acknowledged incompleteness, because it suppresses the question of what is missing.
Generating against intermediate build stages. Including build tools, test frameworks, and compiler dependencies that don't ship to production inflates the SBOM with non-deployed components. Every inflated SBOM produces vulnerability scan noise. That noise erodes team trust and creates organizational pressure to reduce scanning frequency or scope. The program degrades from the inside.
Storing SBOMs as expiring pipeline artifacts. A standard 30-day retention window makes the SBOM useless for vulnerabilities disclosed after that window closes. Impact analysis following a CVE requires historical SBOMs keyed to the specific artifact digests still running in production at the time of disclosure. Those digests may be months old.
Producing SBOMs without VEX statements. Without a formal record of exploitability decisions, the same non-issue requires re-triage on every scan cycle. Security teams operating this way are burning analyst time on problems already assessed and closed. The cumulative cost is significant and entirely preventable.
Not treating generation failures as build failures. A pipeline that continues after a generation error ships an artifact with no provenance record. The intent of the program is subverted at the first inconvenient failure. This is where aspirational policies collapse — the failure mode is invisible until the moment it's consequential.
Running generation on developer machines. Developer machine generation sacrifices the auditability and environment consistency that make CI the authoritative production context. It also exposes the generation process, which runs with elevated access to source and dependency trees, to a significantly larger attack surface than a hardened CI runner. The SBOM produced on a developer machine can't be treated as an authoritative record for compliance or incident response, because the conditions under which it was produced can't be reliably reproduced or independently verified.
The underlying error in all of these patterns is the same — treating the SBOM as a document to be produced rather than a record to be generated. Documents can be assembled from available information. Records are produced at the moment of the event they describe. An SBOM is only trustworthy when it's the latter.


