SBOMs in 2026: The Gap Between Compliance Theater and Real Supply Chain Security
CISA and 19 international partners published joint SBOM guidance. The EU Cyber Resilience Act mandates SBOMs. Yet most companies generate them as a last...
Everyone Has an SBOM. Almost Nobody Uses It.
SBOMs — Software Bills of Materials — were supposed to revolutionize software supply chain security. After the SolarWinds and Log4Shell incidents, the US Executive Order 14028 mandated SBOMs for federal software procurement. The EU Cyber Resilience Act (CRA) now requires SBOMs for all products sold in the EU. CISA, the NSA, and 19 international partners published a joint "Shared Vision of SBOM for Cybersecurity" in 2026.
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 220" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="220" rx="12" fill="#1a1a2e"/><path d="M300,25 L380,55 L380,120 Q380,170 300,195 Q220,170 220,120 L220,55 Z" fill="none" stroke="#6366f1" stroke-width="2.5"/><path d="M300,40 L365,65 L365,118 Q365,160 300,180 Q235,160 235,118 L235,65 Z" fill="#6366f1" opacity="0.15"/><rect x="280" y="95" width="40" height="30" rx="4" fill="#6366f1" opacity="0.9"/><path d="M288,95 L288,82 Q288,72 300,72 Q312,72 312,82 L312,95" fill="none" stroke="#6366f1" stroke-width="2.5"/><circle cx="300" cy="110" r="4" fill="#ffffff"/><text x="90" y="60" text-anchor="middle" fill="#3b82f6" font-size="10" font-family="system-ui">Firewall</text><line x1="130" y1="57" x2="218" y2="57" stroke="#3b82f6" stroke-width="1" stroke-dasharray="3,3"/><text x="90" y="100" text-anchor="middle" fill="#a855f7" font-size="10" font-family="system-ui">WAF</text><line x1="110" y1="97" x2="220" y2="85" stroke="#a855f7" stroke-width="1" stroke-dasharray="3,3"/><text x="90" y="140" text-anchor="middle" fill="#2dd4bf" font-size="10" font-family="system-ui">SSO / MFA</text><line x1="130" y1="137" x2="222" y2="120" stroke="#2dd4bf" stroke-width="1" stroke-dasharray="3,3"/><text x="510" y="60" text-anchor="middle" fill="#f59e0b" font-size="10" font-family="system-ui">TLS/SSL</text><line x1="470" y1="57" x2="382" y2="57" stroke="#f59e0b" stroke-width="1" stroke-dasharray="3,3"/><text x="510" y="100" text-anchor="middle" fill="#3b82f6" font-size="10" font-family="system-ui">RBAC</text><line x1="490" y1="97" x2="380" y2="85" stroke="#3b82f6" stroke-width="1" stroke-dasharray="3,3"/><text x="510" y="140" text-anchor="middle" fill="#a855f7" font-size="10" font-family="system-ui">Audit Logs</text><line x1="470" y1="137" x2="378" y2="120" stroke="#a855f7" stroke-width="1" stroke-dasharray="3,3"/></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">Defense in depth: multiple security layers protect your infrastructure from threats.</p></div>
Every major compliance framework now expects SBOMs. And most companies generate them.
The problem? Most SBOMs are compliance theater. They're generated as the last step of a build pipeline, dumped into an artifact repository, and never looked at again. They don't improve security because nobody consumes them for security decisions.
In March 2026, Manifest released a new SBOM generator for C/C++ — historically the biggest blind spot in SBOM tooling. This is progress. But the tooling gap is only part of the problem. The real gap is between generating SBOMs and using them.
What an SBOM Actually Is
An SBOM is a machine-readable inventory of every component in a software artifact: libraries, frameworks, modules, and their versions, licenses, and relationships.
Two dominant formats:
CycloneDX (OWASP)
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"components": [
{
"type": "library",
"name": "express",
"version": "4.21.1",
"purl": "pkg:npm/[email protected]",
"licenses": [{"license": {"id": "MIT"}}],
"hashes": [
{"alg": "SHA-256", "content": "a1b2c3d4..."}
]
},
{
"type": "library",
"name": "lodash",
"version": "4.17.21",
"purl": "pkg:npm/[email protected]",
"licenses": [{"license": {"id": "MIT"}}]
}
],
"dependencies": [
{
"ref": "pkg:npm/[email protected]",
"dependsOn": ["pkg:npm/[email protected]"]
}
]
}SPDX (Linux Foundation)
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"packages": [
{
"SPDXID": "SPDXRef-Package-express",
"name": "express",
"versionInfo": "4.21.1",
"downloadLocation": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"licenseConcluded": "MIT"
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relationshipType": "DESCRIBES",
"relatedSpdxElement": "SPDXRef-Package-express"
}
]
}Both formats capture the same essential information. CycloneDX is more popular in security contexts, SPDX in compliance and legal contexts.
The Five Stages of SBOM Maturity
Stage 1: No SBOM (Still Common)
Organizations at this stage have no formal component inventory. They might know their direct dependencies but have no visibility into transitive dependencies.
Risk: When a vulnerability like Log4Shell drops, they spend days figuring out if they're affected.
Stage 2: Compliance SBOM (Most Organizations)
SBOMs are generated as the last build step to satisfy procurement requirements:
# Typical CI pipeline — SBOM as afterthought
stages:
- build
- test
- deploy
- generate-sbom # Last step, never consumed
generate-sbom:
stage: generate-sbom
script:
- syft . -o cyclonedx-json > sbom.json
- aws s3 cp sbom.json s3://artifacts/sbom/
# Nobody ever reads this fileProblems:
Stage 3: Integrated SBOM
SBOMs are generated during the build process and integrated with vulnerability scanning:
# Better: SBOM integrated into pipeline
stages:
- build
- generate-sbom
- vulnerability-check
- compliance-check
- deploy
generate-sbom:
stage: generate-sbom
script:
- syft . -o cyclonedx-json > sbom.json
- grype sbom:sbom.json --fail-on critical
artifacts:
paths:
- sbom.json
vulnerability-check:
stage: vulnerability-check
script:
# Check SBOM against known vulnerabilities
- bomber scan sbom.json --provider osv
# Block deployment if critical vulns found
- bomber scan sbom.json --provider osv --fail-on-severity criticalStage 4: Continuous SBOM
SBOMs are continuously updated and monitored — not just at build time:
# Continuous SBOM monitoring service
class SBOMMonitor:
def __init__(self):
self.sbom_store = SBOMDatabase()
self.vuln_feed = VulnerabilityFeed() # OSV, NVD, GitHub Advisory
async def on_new_vulnerability(self, vuln):
"""When a new CVE is published, check all SBOMs."""
affected_components = vuln.affected_packages
for component in affected_components:
# Find all deployments using this component
affected = self.sbom_store.find_by_component(
name=component.name,
version_range=component.vulnerable_versions
)
for deployment in affected:
alert = SecurityAlert(
severity=vuln.severity,
component=component,
deployment=deployment,
remediation=vuln.remediation
)
await self.notify(alert)
async def on_new_deployment(self, sbom):
"""When new code deploys, check SBOM against all known vulns."""
for component in sbom.components:
vulns = self.vuln_feed.check(component)
if vulns:
await self.notify_deployment_risk(sbom, vulns)Stage 5: SBOM-Driven Security (Aspirational)
SBOMs drive automated security decisions:
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 180" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="180" rx="12" fill="#1a1a2e"/><circle cx="60" cy="90" r="20" fill="none" stroke="#3b82f6" stroke-width="2"/><text x="60" y="94" text-anchor="middle" fill="#3b82f6" font-size="11" font-family="system-ui">User</text><rect x="120" y="65" width="95" height="50" rx="8" fill="#6366f1" opacity="0.85"/><text x="167" y="85" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Identity</text><text x="167" y="100" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Verify</text><rect x="250" y="65" width="95" height="50" rx="8" fill="#a855f7" opacity="0.85"/><text x="297" y="85" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Policy</text><text x="297" y="100" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Engine</text><rect x="380" y="65" width="95" height="50" rx="8" fill="#2dd4bf" opacity="0.85"/><text x="427" y="85" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Access</text><text x="427" y="100" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Proxy</text><rect x="510" y="65" width="60" height="50" rx="8" fill="#f59e0b" opacity="0.85"/><text x="540" y="94" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">App</text><defs><marker id="arrow5" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6" fill="#e2e8f0"/></marker></defs><line x1="82" y1="90" x2="118" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><line x1="217" y1="90" x2="248" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><line x1="347" y1="90" x2="378" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><line x1="477" y1="90" x2="508" y2="90" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow5)"/><text x="167" y="140" text-anchor="middle" fill="#94a3b8" font-size="9" font-family="system-ui">MFA + Device</text><text x="297" y="140" text-anchor="middle" fill="#94a3b8" font-size="9" font-family="system-ui">Least Privilege</text><text x="427" y="140" text-anchor="middle" fill="#94a3b8" font-size="9" font-family="system-ui">Encrypted Tunnel</text><text x="300" y="165" text-anchor="middle" fill="#6366f1" font-size="11" font-family="system-ui" font-weight="bold">Never Trust, Always Verify</text></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">Zero Trust architecture: every request is verified through identity, policy, and access proxy layers.</p></div>
The C/C++ Problem (And Manifest's Solution)
SBOM generation for interpreted languages (Python, JavaScript, Ruby) is relatively straightforward — you parse package.json, requirements.txt, or Gemfile.lock and enumerate dependencies.
C and C++ are different. There's no universal package manager. Dependencies are often:
Manifest's March 2026 C/C++ SBOM generator addresses this by: 1. Analyzing build systems (CMake, Make, Meson, Bazel) 2. Scanning binary artifacts for embedded library signatures 3. Matching source code against known open-source packages 4. Tracing dynamic library loading at runtime
This matters because critical infrastructure — operating systems, embedded systems, automotive software, medical devices — is overwhelmingly C/C++. Without accurate C/C++ SBOMs, the most critical software in the world has the worst supply chain visibility.
The EU Cyber Resilience Act Impact
The CRA requires:
1. SBOM generation: All products with digital elements must include an SBOM 2. Vulnerability handling: Manufacturers must actively monitor and patch vulnerabilities in their components 3. Incident reporting: Security incidents related to supply chain compromises must be reported within 24 hours 4. Update mechanism: Products must have a secure update mechanism for at least 5 years
CRA Timeline:
- August 2025: Reporting obligations take effect
- February 2027: Full compliance required
- Non-compliance: Up to €15M or 2.5% of global annual revenueFor any company selling software products in the EU — which includes SaaS companies serving EU customers — SBOM is no longer optional. It's a legal requirement with significant financial penalties.
Building an Effective SBOM Program
Step 1: Choose Your Toolchain
# Generation tools
synft . # Anchore Syft — multi-ecosystem
trivy fs . --format cyclonedx # Aqua Trivy — includes vuln scanning
cdxgen -t python . # CycloneDX generator
# Vulnerability scanning against SBOMs
grype sbom:sbom.json # Anchore Grype
bomber scan sbom.json # Bomber — multi-source vuln checking
osv-scanner --sbom sbom.json # Google OSV scanner
# SBOM management
dependency-track # OWASP Dependency-Track (self-hosted)
guac # Google GUAC (Graph for Understanding
# Artifact Composition)Step 2: Integrate Into CI/CD
# GitLab CI example — SBOM as a first-class citizen
sbom-generate:
stage: build
script:
- syft . -o [email protected] > sbom.json
# Sign the SBOM for integrity
- cosign sign-blob --key cosign.key sbom.json > sbom.sig
artifacts:
paths:
- sbom.json
- sbom.sig
expire_in: 1 year
sbom-vulnerability-check:
stage: test
needs: [sbom-generate]
script:
# Check against multiple vulnerability sources
- grype sbom:sbom.json --fail-on critical
- osv-scanner --sbom sbom.json
allow_failure: false # Block deployment on critical vulns
sbom-license-check:
stage: test
needs: [sbom-generate]
script:
# Check for license compliance
- grant check sbom.json --config license-policy.yaml
allow_failure: false
sbom-publish:
stage: deploy
needs: [sbom-generate, sbom-vulnerability-check, sbom-license-check]
script:
# Publish to Dependency-Track for continuous monitoring
- curl -X POST "$DTRACK_URL/api/v1/bom" \
-H "X-Api-Key: $DTRACK_KEY" \
-H "Content-Type: multipart/form-data" \
-F "project=$PROJECT_UUID" \
-F "[email protected]"Step 3: Deploy Continuous Monitoring
OWASP Dependency-Track is the leading open-source SBOM management platform:
# Docker Compose for Dependency-Track
services:
dependency-track-api:
image: dependencytrack/apiserver:latest
environment:
- ALPINE_DATABASE_URL=jdbc:postgresql://postgres:5432/dtrack
- ALPINE_DATABASE_DRIVER=org.postgresql.Driver
ports:
- "8081:8080"
volumes:
- dt-data:/data
dependency-track-frontend:
image: dependencytrack/frontend:latest
environment:
- API_BASE_URL=http://localhost:8081
ports:
- "8080:8080"
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_DB=dtrack
- POSTGRES_PASSWORD=${DT_DB_PASSWORD}
volumes:
- pg-data:/var/lib/postgresql/dataDependency-Track continuously monitors your SBOMs against the NVD, GitHub Advisory Database, and OSV, alerting you when new vulnerabilities affect your deployed software.
Step 4: Implement SBOM Attestation
SBOMs should be signed and attested to prove they haven't been tampered with:
# Generate SBOM
syft . -o cyclonedx-json > sbom.json
# Create in-toto attestation
cosign attest --key cosign.key \
--type cyclonedx \
--predicate sbom.json \
registry.example.com/myapp:v2.1.0
# Verify attestation before deployment
cosign verify-attestation \
--key cosign.pub \
--type cyclonedx \
registry.example.com/myapp:v2.1.0This creates a cryptographic chain of trust: the SBOM was generated by your build system, hasn't been modified, and accurately represents the software artifact.
The VEX Companion
Vulnerability Exploitability eXchange (VEX) documents complement SBOMs by stating whether a known vulnerability in a component actually affects your product:
{
"document": {
"category": "csaf_vex",
"title": "VEX for MyApp v2.1.0"
},
"vulnerabilities": [
{
"cve": "CVE-2024-12345",
"product_status": {
"known_not_affected": ["MyApp v2.1.0"]
},
"threats": [
{
"details": "The vulnerable function in lodash is not called by our application. Import chain exists but the affected code path is unreachable."
}
]
}
]
}Without VEX, every vulnerability in your SBOM generates an alert. With VEX, you communicate which vulnerabilities are actually exploitable in your context — reducing alert fatigue by 60-80%.
Metrics That Matter
Track these metrics to measure your SBOM program's effectiveness:
|--------|--------|-----|
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 200" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="200" rx="12" fill="#1a1a2e"/><text x="80" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Input</text><circle cx="80" cy="50" r="14" fill="none" stroke="#3b82f6" stroke-width="2"/><circle cx="80" cy="100" r="14" fill="none" stroke="#3b82f6" stroke-width="2"/><circle cx="80" cy="150" r="14" fill="none" stroke="#3b82f6" stroke-width="2"/><text x="230" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Hidden</text><circle cx="230" cy="45" r="14" fill="#6366f1" opacity="0.8"/><circle cx="230" cy="85" r="14" fill="#6366f1" opacity="0.8"/><circle cx="230" cy="125" r="14" fill="#6366f1" opacity="0.8"/><circle cx="230" cy="165" r="14" fill="#6366f1" opacity="0.8"/><text x="380" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Hidden</text><circle cx="380" cy="55" r="14" fill="#a855f7" opacity="0.8"/><circle cx="380" cy="100" r="14" fill="#a855f7" opacity="0.8"/><circle cx="380" cy="145" r="14" fill="#a855f7" opacity="0.8"/><text x="520" y="25" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Output</text><circle cx="520" cy="80" r="14" fill="none" stroke="#2dd4bf" stroke-width="2"/><circle cx="520" cy="130" r="14" fill="none" stroke="#2dd4bf" stroke-width="2"/><line x1="94" y1="50" x2="216" y2="45" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="50" x2="216" y2="85" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="50" x2="216" y2="125" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="50" x2="216" y2="165" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="45" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="85" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="125" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="100" x2="216" y2="165" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="45" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="85" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="125" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="94" y1="150" x2="216" y2="165" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="45" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="45" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="45" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="85" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="85" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="85" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="125" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="125" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="125" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="165" x2="366" y2="55" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="165" x2="366" y2="100" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="244" y1="165" x2="366" y2="145" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="55" x2="506" y2="80" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="55" x2="506" y2="130" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="100" x2="506" y2="80" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="100" x2="506" y2="130" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="145" x2="506" y2="80" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/><line x1="394" y1="145" x2="506" y2="130" stroke="#e2e8f0" stroke-width="0.5" opacity="0.3"/></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">Neural network architecture: data flows through input, hidden, and output layers.</p></div>
The Bottom Line
SBOMs are now legally required for many organizations and expected by most enterprise procurement processes. But generating an SBOM and filing it away is worse than useless — it creates a false sense of security.
The organizations that benefit from SBOMs are those that treat them as living security artifacts: generated during build, checked against vulnerability databases before deployment, continuously monitored after deployment, and attested for integrity.
Stop generating SBOMs as compliance artifacts. Start using them as security tools. The difference between the two is the difference between checking a box and actually securing your supply chain.
Need help with security?
TechSaaS provides expert consulting and managed services for cloud infrastructure, DevOps, and AI/ML operations.