CRA SBOM Storage, Vulnerability Tracking & Art.14 Reporting 2026: A Developer Operations Guide
Post #4 in the sota.io EU CRA SBOM Developer Guide Series (2026)
Most teams treat SBOM generation as a pipeline artifact — something that gets produced, validated, and archived into object storage. The Cyber Resilience Act changes that model entirely. An SBOM is not a build artifact; it is a legal compliance document that must be retrievable for up to ten years, kept current throughout the product lifecycle, and directly actionable when a vulnerability is discovered. The moment a CVE affects a component in your SBOM, a regulatory clock may start running.
This is the fourth post in our five-part CRA SBOM series. Post #1 covered the Art.13/Annex VII regulatory foundation. Post #2 compared CycloneDX and SPDX formats. Post #3 covered CI/CD pipeline automation. Here we address the less-discussed but equally critical operational layer: how to store SBOMs, how to track vulnerabilities against them, and how to execute the Art.14 reporting cascade when an actively exploited vulnerability is discovered.
SBOM Retention: What Art.31 Actually Requires
Art.31 of the CRA establishes the retention timeline for technical documentation, including SBOM. Manufacturers must retain technical documentation for the greater of ten years after market placement or the duration of the product's supported lifecycle.
For a typical SaaS product with a rolling release model and a five-year support window, this means:
- If you ship a release in June 2026, its SBOM must be retained until at least June 2036
- If you decommission a release in 2028 but initially placed it on the market in 2026, the ten-year clock from 2026 still applies — documentation must be kept until 2036
- Every SBOM update produced during the lifecycle (after patching, dependency upgrades, or component changes) must also be retained, not replaced
This creates a version-controlled SBOM archive requirement, not a single-file storage problem. Teams need an SBOM store that maintains immutable historical versions alongside the current state.
What Must Be Stored
Under Annex VII, the SBOM must contain sufficient information to identify every software component and its known vulnerability status. In practice, this means storing alongside each SBOM version:
- The SBOM itself (CycloneDX JSON/XML or SPDX 2.3+)
- The build provenance attestation (who generated it, when, from which source commit)
- Any VEX documents produced at release time (see below)
- The vulnerability scan results that informed the VEX assessment
VEX Documents: Connecting SBOM to Vulnerability Reality
A common gap in SBOM implementations is the absence of VEX (Vulnerability Exploitability eXchange) documents. An SBOM tells a market surveillance authority which components are in your product. A VEX document tells them which CVEs affecting those components are actually exploitable in your deployment context — and which are not.
Without VEX, every CVE that touches any component in your SBOM is theoretically open against your product. A typical SBOM for a Node.js service might include 800+ transitive dependencies; at any given time, 50-100 CVEs may affect those packages. Most will not be exploitable in your specific configuration. VEX provides the mechanism to assert this formally.
The Four VEX Statuses
The OpenVEX specification (implemented by CycloneDX 1.5+ and SPDX 2.3+) defines four statuses for each CVE/component pair:
| Status | Meaning |
|---|---|
not_affected | The CVE affects the component but not this product (wrong config, unreachable code path) |
affected | The CVE affects this product — remediation in progress or pending |
fixed | The CVE was present and has been remediated in a specific version |
under_investigation | Assessment is in progress; status not yet determined |
Producing VEX in Your Pipeline
For CycloneDX pipelines:
# Generate VEX document alongside SBOM (CycloneDX CLI)
cyclonedx vex create \
--sbom sbom.cdx.json \
--output vex-$(date +%Y%m%d).cdx.json
# Add individual assessments
cyclonedx vex affect \
--vex vex-$(date +%Y%m%d).cdx.json \
--component "pkg:npm/lodash@4.17.21" \
--vulnerability CVE-2021-23337 \
--analysis "not_affected" \
--justification "Affected code path (cloneDeep with prototype pollution) is not called by this application; all input is sanitised upstream"
For SPDX pipelines, use osv-scanner with --format sarif and then convert to SPDX Annotations using spdx-tools.
Vulnerability Tracking: The SBOM-to-CVE Pipeline
Storing an SBOM is necessary but not sufficient. The CRA requires manufacturers to actively handle vulnerabilities — which means continuously scanning your SBOM against vulnerability databases and triaging results.
Recommended Scanning Stack
The open-source vulnerability scanning ecosystem provides good coverage for CRA compliance without proprietary lock-in:
Primary source: OSV.dev Open Source Vulnerabilities (Google) aggregates vulnerability data from GitHub Advisory Database, PyPI Advisory Database, npm Advisories, RubyGems Advisories, and the NVD. It provides a free API and handles transitive vulnerability analysis.
# Install osv-scanner
go install github.com/google/osv-scanner/cmd/osv-scanner@latest
# Scan against SBOM
osv-scanner --sbom sbom.cdx.json --format json --output vuln-$(date +%Y%m%d).json
# Parse results and filter for affected/under-investigation
python3 scripts/triage_vulns.py vuln-$(date +%Y%m%d).json
Secondary source: NVD (NIST National Vulnerability Database) For CVEs not in OSV, query the NVD REST API (v2.0) directly. Important for CRA reporting: ENISA's EUVD (European Vulnerability Database) is the reference database for EU market surveillance. EUVD correlates with NVD CVEs, so NVD coverage is effectively required.
Grype (Anchore) for container SBOMs
grype sbom:./sbom.cdx.json --output cyclonedx-json --file vuln-grype-$(date +%Y%m%d).cdx.json
Triage Workflow
Effective vulnerability management under the CRA requires a structured triage SOP:
- Discovery — Automated nightly scan produces new CVE matches against current SBOM
- Classification — Is this CVE exploitable in our configuration? (VEX status:
not_affected/under_investigation) - Prioritisation — CVSS ≥ 7.0 + exploitable = P0. CVSS < 7.0 + not exploitable = backlog
- Remediation — Patch and update SBOM. Produce new VEX
fixedassertion - Reporting trigger check — Is this vulnerability being actively exploited in the wild? If yes: Art.14 clock starts
CRA Art.14 Reporting: The Three-Tier Cascade
When a manufacturer discovers that a vulnerability in their product is being actively exploited, Art.14 triggers a mandatory three-tier reporting sequence to ENISA and the national CSIRT coordinator.
"Actively exploited" means the vulnerability is being used in actual attacks in the wild — not merely that a CVE exists. The trigger is typically a threat intelligence signal (CISA KEV entry, ENISA EUVD flag, credible public PoC with observed exploitation).
The Timeline
| Tier | Deadline | Content Required |
|---|---|---|
| Early warning | 24 hours after discovery | Affected product name/version, CVE ID (if known), whether a fix is available, initial impact assessment |
| Full notification | 72 hours after discovery | Full technical details, affected user scope, interim mitigations, timeline to patch |
| Final report | 14 days after discovery | Root cause analysis, complete remediation, patched version details, lessons learned |
ENISA operates a single reporting platform (currently being built out under Art.14 implementation). Until the EU-wide platform is production-ready, national CSIRTs serve as the primary reporting recipients. Your national CSIRT contact depends on your country of establishment, not the country of your customers.
What Your SBOM Enables in Art.14 Reporting
A well-maintained SBOM dramatically reduces the time to produce a compliant early warning. The 24-hour window is tight — many teams cannot manually identify the full scope of an affected deployment within that window without automation.
With an up-to-date SBOM and vulnerability tracking pipeline:
- Affected product versions are instantly queryable (
osv-scanner --sbom) - VEX history shows whether this CVE was previously assessed
- Component ownership maps to responsible engineering team
- Customer exposure scope is derivable from deployment inventory
Without this infrastructure, teams typically spend the first 12-18 hours just scoping the impact — leaving 6-12 hours for actual notification drafting and submission.
SBOM Storage Architecture: Practical Options
Option 1: OCI Artifact Registry (Recommended for Container Workflows)
For containerised products, storing SBOMs as OCI artifacts alongside the container image is the most operationally clean approach. The SBOM is cryptographically linked to the image digest via OCI referrers.
# Attach SBOM to image in registry using ORAS
oras attach \
myregistry.azurecr.io/myapp:v1.2.3 \
--artifact-type "application/vnd.cyclonedx+json" \
sbom.cdx.json:application/vnd.cyclonedx+json
# Retrieve SBOM for any image version
oras discover myregistry.azurecr.io/myapp:v1.2.3
For CRA compliance, the registry must support immutable tags (no overwriting of existing artifact digests) and must be retained for the Art.31 period.
Option 2: S3-Compatible Object Storage with Version Locking
For non-containerised SaaS products, S3-compatible object storage with versioning and object lock (WORM — write once read many) satisfies the immutability requirement.
# Upload SBOM with version lock (MinIO / Hetzner Object Storage)
mc cp sbom.cdx.json \
minio/sbom-archive/myapp/v1.2.3/sbom-$(date +%Y%m%d).cdx.json
# Enable versioning on bucket
mc version enable minio/sbom-archive
# Enable object retention (WORM — prevents deletion)
mc retention set --default COMPLIANCE "10y" minio/sbom-archive
Option 3: Dedicated SBOM Management Platform
Commercial SBOM platforms (e.g., Anchore Enterprise, FOSSA, DependencyTrack) provide purpose-built storage with vulnerability correlation, VEX management, and audit-ready reporting. DependencyTrack is notable for being open-source and EU-deployable.
# Push SBOM to DependencyTrack
curl -X PUT \
-H "X-Api-Key: ${DTRACK_API_KEY}" \
-H "Content-Type: multipart/form-data" \
-F "autoCreate=true" \
-F "projectName=myapp" \
-F "projectVersion=v1.2.3" \
-F "bom=@sbom.cdx.json" \
https://dtrack.internal/api/v1/bom
The Jurisdiction Risk: CLOUD Act and SBOM Storage
This section explains a compliance risk that is rarely discussed but directly relevant to CRA enforcement.
Your SBOM contains the complete inventory of your software supply chain, including third-party components, open-source libraries, and their versions. A market surveillance authority requesting your SBOM documentation is an expected and legitimate access pathway. A US law enforcement request under the CLOUD Act (18 U.S.C. § 2713) is a different and less expected pathway — but equally real.
The CLOUD Act grants US law enforcement authority to compel US-incorporated cloud providers to produce data stored anywhere in the world, including in EU data centres. This includes SBOM documents stored in AWS S3 (even in eu-central-1), Azure Blob Storage (even in West Europe), or GitHub Container Registry.
The practical risk:
- Your SBOM may be subpoenaed in the context of a criminal investigation related to a supply chain attack
- A US-accessible SBOM could expose information about your software supply chain, internal tooling, and dependency versions to actors outside the EU regulatory framework
- EU GDPR-protected information embedded in SBOMs (e.g., developer names in build attestations) may be transferred under CLOUD Act without EU adequacy mechanisms
Storing SBOM documentation on EU-native infrastructure — Hetzner Object Storage (Germany), OVHcloud (France), or a self-hosted MinIO cluster on Hetzner — keeps your compliance evidence within EU jurisdiction and accessible only to EU market surveillance authorities through proper legal channels.
sota.io deployments run exclusively on Hetzner in Germany. SBOM artifacts stored via sota.io's OCI registry or S3-compatible storage endpoints are outside CLOUD Act reach.
Full Storage and Reporting Checklist
SBOM Storage (Art.31 Compliance)
- SBOM versioned and immutable — no overwrite of existing version records
- Retention policy set to minimum 10 years (WORM policy or lifecycle lock)
- Build provenance attestation stored alongside each SBOM version
- Storage on EU-jurisdiction infrastructure (Hetzner/OVH/IONOS — not AWS/Azure/GCP)
VEX Document Management
- VEX produced at every release alongside SBOM
- All CVSS ≥ 7.0 vulnerabilities assessed with explicit
not_affectedoraffected+ justification - VEX documents versioned and linked to corresponding SBOM version
- VEX update triggered on new CVE publication affecting stored components
Vulnerability Tracking Pipeline
- Automated daily scan with
osv-scanner --sbomor equivalent - NVD/EUVD query for CVEs not in OSV
- Triage SLA defined: P0 (CVSS ≥ 7.0 + exploitable) ≤ 7 days to patch
- Escalation path documented: who owns Art.14 notification when active exploitation detected?
Art.14 Reporting Readiness
- National CSIRT contact endpoint documented and tested
- 24-hour early warning template ready to draft and submit
- SBOM query runbook available: "given CVE X, which product versions are affected?"
- On-call rotation includes Art.14 reporting as a defined responsibility
Next in the Series
Post #5 closes the series with a comprehensive developer audit checklist covering all five SBOM compliance dimensions: format, generation, storage, vulnerability management, and Art.14 readiness. It includes a self-assessment scoring rubric suitable for use in pre-market conformity assessment preparation.
The EU Cyber Resilience Act (Regulation (EU) 2024/2847) applies to products with digital elements placed on the EU market. CRA reporting obligations under Art.14 become enforceable from 11 September 2026. This post is part of the sota.io EU CRA SBOM Developer Guide Series.
EU-Native Hosting
Ready to move to EU-sovereign infrastructure?
sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.