2026-05-04·13 min read·sota.io team

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 ScopePotentially Out of Scope
Commercial software (SaaS, on-premise)Free and open source software (FOSS) distributed as-is with no commercial support
B2B SaaS productsPure services with no software component
APIs sold to other manufacturersInternal tools not placed on the market
SDKs and libraries if bundled with a productFOSS 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:

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:

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 CategoryDetectionInternal FixENISA Notification
Actively exploited (KEV/EPSS >0.9)Immediate24h to patch + mitigateWithin 24h of discovery
Critical CVSS ≥ 9.0 (not KEV)Within 24h72hWithin 72h if actively exploited
High CVSS 7.0–8.9Within 48h7 daysOnly if confirmed exploited
Medium/LowWeekly scanBest effortNot required

Sources to check daily for "actively exploited" status:


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:

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:

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:

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:


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:

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

FormatCRA AlignmentTooling SupportMachine-ReadableRecommended For
CycloneDX 1.6 JSON✅ BestSyft, Trivy, CycloneDX CLIAll new projects
SPDX 2.3 JSON✅ GoodSPDX tools, SyftIf upstream uses SPDX
SPDX 2.3 TV⚠️ PartialSPDX toolsLegacy toolchains
CycloneDX XML✅ GoodWide supportXML-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

DateObligation Active
February 2025CRA enters into force (publication + 20 days). NLF framework applies.
September 11, 2026CRA Art. 14 + Annex II: SBOM + Vulnerability reporting mandatory
December 11, 2027Full 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

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.