CRA September 2026: SBOM Generation and Vulnerability Reporting Checklist for Developers
Post #815 in the sota.io EU Compliance Series
On September 11, 2026, two obligations under the EU Cyber Resilience Act (CRA) become mandatory for all software manufacturers selling products in the EU: Software Bill of Materials (SBOM) generation and 24-hour vulnerability reporting to ENISA. The countdown is 129 days.
Most developer guides cover why these obligations exist. This guide covers how to implement them — with specific tools, CI/CD pipeline changes, ENISA notification templates, and a 12-point checklist you can work through in a single sprint.
Who Is In Scope
The CRA applies to "products with digital elements" — software or hardware with network connectivity or data-processing capability. If you ship software to EU customers (including SaaS deployed in the EU), you are a manufacturer under the CRA.
Key scope boundaries:
| In Scope | Potentially Out of Scope |
|---|---|
| Commercial software (SaaS, on-premise) | Free and open source software (FOSS) distributed as-is with no commercial support |
| B2B SaaS products | Pure services with no software component |
| APIs sold to other manufacturers | Internal tools not placed on the market |
| SDKs and libraries if bundled with a product | FOSS components where you are downstream integrator (upstream manufacturer is responsible) |
Important FOSS clarification (CRA Recital 18): If you are an open source maintainer who also provides commercial support, warranty, or monetised services around the software, you are in scope. Pure community projects with no commercial model have narrower obligations, but the line is not simple. When in doubt, treat your software as in scope.
The Two September 2026 Obligations
Obligation 1: SBOM (CRA Annex II, point 1)
CRA Annex II requires manufacturers to provide a "software bill of materials in a machine-readable format" covering at minimum:
- Top-level components contained in the product
- Dependencies (direct and transitive are best practice)
- Component names, versions, and suppliers
- Dependency relationships
This SBOM must be available to users and maintained throughout the product support period.
Obligation 2: Vulnerability Reporting (CRA Art. 14)
When a manufacturer learns of an actively exploited vulnerability in their product:
- Within 24 hours: Notify ENISA and relevant national CSIRT (early warning)
- Within 72 hours: Submit a full vulnerability notification with initial assessment and remediation status
- After resolution: Submit a final report
The reporting goes via the ENISA Single Reporting Platform (https://www.enisa.europa.eu/topics/incident-response/reporting). Member states have designated national CSIRTs as the primary contact point; Germany uses BSI (cert@bsi.bund.de), France uses ANSSI, Netherlands uses NCSC-NL.
The 12-Point Implementation Checklist
1. Choose Your SBOM Toolchain
Three tools dominate EU-compliant SBOM generation:
Syft (Anchore, open source):
# Install
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# Generate CycloneDX 1.6 SBOM for a container image
syft ghcr.io/your-org/your-app:latest -o cyclonedx-json > sbom.cdx.json
# Generate for a local directory
syft dir:/path/to/your/app -o cyclonedx-json > sbom.cdx.json
CycloneDX CLI (OWASP, open source — aligns with CRA Annex II format requirements):
# Node.js projects
npm install -g @cyclonedx/cyclonedx-npm
cyclonedx-npm --output-format json --output-file sbom.cdx.json
# Python projects
pip install cyclonedx-bom
cyclonedx-py poetry --output-format json --outfile sbom.cdx.json
# Java projects (Maven plugin)
mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom
Trivy (Aqua Security — combines SBOM generation + vulnerability scanning):
# Install
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Generate SBOM + vulnerability scan in one pass
trivy image --format cyclonedx --output sbom.cdx.json your-app:latest
trivy fs --format cyclonedx --output sbom.cdx.json /path/to/app
Recommendation: Use Syft for SBOM generation and Trivy for vulnerability scanning. Both output CycloneDX 1.6, the format best aligned with CRA Annex II requirements.
2. Automate SBOM Generation in CI/CD
The SBOM must reflect the shipped artifact, not a development snapshot. Add SBOM generation as a mandatory step in your release pipeline.
GitHub Actions example:
name: Build and Generate SBOM
on:
push:
branches: [main]
release:
types: [published]
jobs:
build-and-sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build container image
run: docker build -t ${{ github.repository }}:${{ github.sha }} .
- name: Generate SBOM (CycloneDX)
uses: anchore/sbom-action@v0
with:
image: ${{ github.repository }}:${{ github.sha }}
format: cyclonedx-json
output-file: sbom-${{ github.sha }}.cdx.json
- name: Upload SBOM as release artifact
uses: actions/upload-artifact@v4
with:
name: sbom-${{ github.sha }}
path: sbom-${{ github.sha }}.cdx.json
retention-days: 2555 # 7 years — CRA support period best practice
3. Set Up Automated Vulnerability Scanning
Vulnerability scanning must be continuous — not just at build time. New CVEs emerge daily, and CRA Art. 14 triggers as soon as you learn of an actively exploited vulnerability in your product.
Trivy continuous scan (daily cron):
# Scan running container image for new CVEs
trivy image \
--exit-code 1 \
--severity CRITICAL,HIGH \
--vuln-type os,library \
--format json \
--output vuln-report-$(date +%Y%m%d).json \
your-app:latest
# In CI: fail build on CRITICAL CVEs
trivy image --exit-code 1 --severity CRITICAL your-app:latest
Grype (alternative scanner, strong for SBOM-based scanning):
# Install
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# Scan using an existing SBOM (no image pull required)
grype sbom:./sbom.cdx.json --output json > vuln-report.json
# Scan and filter by KEV (CISA Known Exploited Vulnerabilities)
grype sbom:./sbom.cdx.json --add-cpes-if-none --output json \
| jq '.matches[] | select(.vulnerability.epss.percentile > 0.9)'
4. Define CVE Triage SLAs
Not all vulnerabilities require 24-hour ENISA reporting. The CRA Art. 14 trigger is specifically "actively exploited vulnerabilities." Define internal SLAs that align with this:
| CVE Category | Detection | Internal Fix | ENISA Notification |
|---|---|---|---|
| Actively exploited (KEV/EPSS >0.9) | Immediate | 24h to patch + mitigate | Within 24h of discovery |
| Critical CVSS ≥ 9.0 (not KEV) | Within 24h | 72h | Within 72h if actively exploited |
| High CVSS 7.0–8.9 | Within 48h | 7 days | Only if confirmed exploited |
| Medium/Low | Weekly scan | Best effort | Not required |
Sources to check daily for "actively exploited" status:
- CISA KEV catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog (CSV feed available)
- EPSS scores: https://api.first.org/data/v1/epss (high score = high exploitation probability)
- NVD: https://nvd.nist.gov/vuln/search (filter:
hasKev:1)
5. Create Your ENISA Reporting Workflow
When a vulnerability triggers the 24h notification, you need a documented internal process:
Step 1 — 24h Early Warning (CRA Art. 14(1)):
Submit to: https://vulnerability.enisa.europa.eu/report (ENISA single reporting platform, goes live Q3 2026)
Until the platform launches, submit via national CSIRT:
- DE: BSI CERT: https://www.bsi.bund.de/EN/IT-Security-Incidents/Reporting/
- FR: ANSSI: https://www.cert.ssi.gouv.fr/
- NL: NCSC-NL: https://www.ncsc.nl/contact/kwetsbaarheid-melden
Minimum content for 24h early warning:
Subject: CRA Art.14 Early Warning — [Product Name] [CVE-ID]
- Product name and version
- CVE identifier (if assigned)
- Short description of the vulnerability
- Confirmation: actively exploited in the wild [Y/N]
- Immediate mitigation steps taken or planned
- Contact person name + email
Step 2 — 72h Full Notification (CRA Art. 14(2)):
- Full technical description of the vulnerability
- Affected versions (include SBOM component reference)
- CVSS v3.1 score and vector string
- Evidence of active exploitation (URL to PoC, threat intel source)
- Remediation plan with timeline
- Patch version (if available) or workaround
- Whether users have been notified
6. Publish a Coordinated Vulnerability Disclosure (CVD) Policy
CRA Art. 15 requires manufacturers to have a CVD policy. This is public-facing and must include:
- A clear submission channel (email or web form)
- Expected response time for acknowledgement (best practice: 5 business days)
- Scope definition (what is in scope for security reports)
- Safe harbor statement for good-faith researchers
- Process for coordinated disclosure timing
Minimum viable CVD policy URL: https://yourdomain.com/.well-known/security.txt
security.txt format (RFC 9116):
Contact: security@yourdomain.com
Expires: 2027-05-04T00:00:00.000Z
Acknowledgments: https://yourdomain.com/security/hall-of-fame
Policy: https://yourdomain.com/security/vulnerability-disclosure-policy
Preferred-Languages: en, de
7. Audit Your EOL Dependencies
CRA Annex I Part II, point 2 requires manufacturers to "identify and document vulnerabilities and components contained in the product, including by drawing up a software bill of materials."
Undeclared EOL dependencies are a compliance gap. Run a lifecycle audit:
# Node.js — check for deprecated/EOL packages
npx npm-check-updates --target minor
npx node-version-check # Checks Node.js version against EOL schedule
# Python
pip install pip-audit
pip-audit --output json > pip-audit-report.json
# Check Python dependency EOL at endoflife.date
curl -s https://endoflife.date/api/python.json | python3 -c "
import json, sys
data = json.load(sys.stdin)
import datetime
today = datetime.date.today()
for release in data:
eol = datetime.date.fromisoformat(release['eol'])
if eol < today:
print(f'EOL: Python {release[\"cycle\"]} ({release[\"eol\"]})')
"
# Java — check via OWASP Dependency Check
docker run --rm \
-v $(pwd):/src \
owasp/dependency-check \
--project "MyApp" \
--scan /src \
--format JSON \
--out /src/dependency-check-report
8. Set Up a Vulnerability Tracking Register
CRA Art. 13(6) requires manufacturers to address vulnerabilities "without delay." A documented tracking register proves due diligence:
vulnerability-register.csv:
CVE-ID | Discovered | Component | Severity | ENISA-Notified | Patched | Patch-Version | Notes
CVE-2025-XXXX | 2026-01-15 | log4j 2.14.0 | CRITICAL | 2026-01-15 24h | 2026-01-16 | v2.1.4 | KEV confirmed
Keep this register for the duration of the product support period (typically 5+ years for CRA compliance). Store in version control alongside your SBOM.
9. Document Your Product Support Period
CRA Art. 13(8) requires manufacturers to define and document the support period during which security updates are provided. This must be:
- Clearly stated in product documentation
- At least 5 years for most products (proportionate to expected lifetime)
- Made available to users before and during use
Example product documentation clause:
Security Support Period: This product (version X.Y and above)
receives security updates until [DATE]. After this date, we
recommend migrating to a supported version. Security advisories
are published at https://yourdomain.com/security/advisories.
10. Establish Supplier SBOM Requirements
If your product includes third-party components (libraries, SDKs, services), you must assess their SBOM practices. CRA Art. 13(5) requires manufacturers to verify that components from suppliers don't introduce vulnerabilities.
Practical steps:
- Add a security questionnaire to vendor onboarding: "Do you provide a CRA-compliant SBOM?"
- For critical dependencies: request SBOM as a condition of contract renewal
- For open source: check whether the project maintains a VEX (Vulnerability Exploitability eXchange) document
11. Configure Automated Patch Release Pipeline
CRA Annex I Part II, point 8 requires security updates to be "deployable separately from functionality updates." This means:
# .github/workflows/security-patch.yml
name: Security Patch Release
on:
workflow_dispatch:
inputs:
cve_id:
description: 'CVE being patched'
required: true
severity:
description: 'CRITICAL / HIGH'
required: true
jobs:
security-patch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create security-only branch
run: git checkout -b security/patch-${{ github.event.inputs.cve_id }}
# ... patch steps ...
- name: Tag as security release
run: |
git tag -a "v$VERSION-sec" -m "Security patch: ${{ github.event.inputs.cve_id }}"
git push origin "v$VERSION-sec"
- name: Generate updated SBOM
uses: anchore/sbom-action@v0
with:
format: cyclonedx-json
output-file: sbom-security-${{ github.event.inputs.cve_id }}.cdx.json
12. Prepare Your CRA Technical File
CRA Art. 31(3) requires manufacturers to maintain a technical documentation file. SBOM and vulnerability records are key components. The file must include:
- Product description and intended use
- Design and development documentation
- Risk assessment (Art. 10)
- SBOM (Annex II, point 1) — critical for September 2026
- Test reports and conformity evidence
- Copy of EU Declaration of Conformity (Art. 23)
- Vulnerability handling policy
- Security update history
Keep this file for 10 years after placing the product on the market. For SaaS products, "placing on the market" is each significant version release.
SBOM Format Comparison
| Format | CRA Alignment | Tooling Support | Machine-Readable | Recommended For |
|---|---|---|---|---|
| CycloneDX 1.6 JSON | ✅ Best | Syft, Trivy, CycloneDX CLI | ✅ | All new projects |
| SPDX 2.3 JSON | ✅ Good | SPDX tools, Syft | ✅ | If upstream uses SPDX |
| SPDX 2.3 TV | ⚠️ Partial | SPDX tools | ✅ | Legacy toolchains |
| CycloneDX XML | ✅ Good | Wide support | ✅ | XML-required pipelines |
| CSV/proprietary | ❌ Not compliant | — | ⚠️ | Not recommended |
Recommendation: CycloneDX 1.6 JSON. ENISA's draft guidance (published Q1 2026) references CycloneDX as the preferred format for CRA notifications. Syft generates CycloneDX 1.6 natively as of v1.11.
Infrastructure Consideration: EU-Hosted Disclosure Endpoints
Your CVD policy endpoint, security.txt, and vulnerability advisory pages are legally required to be accessible. If these are hosted on US infrastructure (AWS us-east, Cloudflare Pages, GitHub Pages with US CDN nodes), they could theoretically become unavailable under US government compulsion — an edge case but a real CLOUD Act risk for critical infrastructure vendors.
For SaaS products classified as critical (NIS2 essential entities, CRA critical class II), consider hosting your security disclosure infrastructure in the EU. A minimal setup:
security.yourdomain.com → EU PaaS (hosted in DE/FR/NL)
GET /.well-known/security.txt → static file
GET /security/advisories → advisory index (static JSON + HTML)
POST /security/report → vulnerability intake form
sota.io deploys your security disclosure infrastructure on EU-incorporated, EU-controlled servers with no US parent company exposure to CLOUD Act orders. See CRA Art. 25 Conformity Assessment and EU Hosting.
Enforcement Timeline
| Date | Obligation Active |
|---|---|
| February 2025 | CRA enters into force (publication + 20 days). NLF framework applies. |
| September 11, 2026 | CRA Art. 14 + Annex II: SBOM + Vulnerability reporting mandatory |
| December 11, 2027 | Full CRA compliance mandatory (conformity assessment, CE marking) |
The September 2026 deadline is 129 days away. A single sprint (2 weeks) is enough to implement the basics: SBOM generation in CI/CD, Trivy scanning, CVD policy page, and the ENISA notification workflow. The remaining 10 checklist items can be rolled out over the following month.
Quick Reference: CRA Art. 14 Notification Timeline
Day 0: You learn of an actively exploited vulnerability
↓
Day 0 + 24h: Submit EARLY WARNING to ENISA/national CSIRT
- Product + version
- CVE identifier (or internal ID)
- Is it actively exploited: YES
- Immediate mitigation
↓
Day 0 + 72h: Submit FULL NOTIFICATION
- Complete technical description
- CVSS score + vector
- Affected component (reference to SBOM entry)
- Remediation plan + timeline
↓
Patch released: Submit FINAL REPORT
- Patch version
- Verification of fix
- User notification status
Further Reading
- CRA Art. 11: Vulnerability Handling, SBOM, and Responsible Disclosure
- CRA Art. 15: Coordinated Vulnerability Disclosure Policy
- CRA Art. 13: Manufacturer Obligations and Security by Design
- ENISA Package Manager Security Advisory: CRA Supply Chain
- CRA Art. 16: Vulnerability Reporting to ENISA
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.