2026-04-19·14 min read·

CRA Art.9: Due Diligence for Third-Party Components — SBOM, Open Source Integration, Supply Chain Obligations (Developer Guide 2026)

Post #463 in the sota.io EU Cyber Compliance Series

Modern software is assembled, not written from scratch. A typical web application bundles hundreds of npm packages. A firmware image includes third-party cryptographic libraries, RTOS components, and vendor SDKs. A mobile application links against platform frameworks and embedded analytics libraries. In every case, the final product carries not just the manufacturer's code but also the security posture — and vulnerabilities — of every component it integrates.

The EU Cyber Resilience Act (Regulation (EU) 2024/2847, "CRA") accounts for this reality in Article 9, which imposes a due diligence obligation on manufacturers when integrating third-party components — both commercial and open source — into products with digital elements.

Article 9 is not a checkbox. It is a process requirement: manufacturers must actively identify what they have integrated, monitor those components for vulnerabilities, and take action when problems appear. Failure to maintain this process is a CRA non-conformity, regardless of whether any specific component vulnerability has been exploited.

This guide covers:

What Article 9 Requires

CRA Art.9 states that manufacturers shall exercise due diligence when integrating components from third parties into their products with digital elements. This obligation operates at two levels:

1. Identification and documentation. Manufacturers must identify all third-party components integrated into their product and document them in a software bill of materials (SBOM). The SBOM must be machine-readable.

2. Vulnerability monitoring. When a third-party component contains a known vulnerability, the manufacturer cannot simply ship the product with that vulnerability present. Art.9(2) creates a direct link to Art.10 (vulnerability handling): if a manufacturer becomes aware that an integrated component has a vulnerability that affects the security of their product, they must treat it as a product vulnerability under Art.10.

3. Open source components. Art.9(3) addresses the specific situation of open source software. Manufacturers who integrate open source components must exercise reasonable care to verify that those components do not contain known vulnerabilities at the time of integration. For ongoing maintenance, manufacturers must monitor published vulnerability databases (CVEs, OSV, vendor advisories) for vulnerabilities in their open source dependencies.

The net effect: a manufacturer cannot outsource their vulnerability responsibility to their suppliers. If a third-party library has a known CVE, and the manufacturer ships that library in their product, the manufacturer is non-compliant under Art.9 — even if the library publisher has not yet issued a patch.

Who Art.9 Applies To

Art.9 applies to any manufacturer as defined under CRA Art.3(12): a natural or legal person who develops or manufactures products with digital elements, or who has products designed or manufactured and markets them under their own name or trademark.

This includes:

Upstream suppliers (component manufacturers) who supply components to another manufacturer are not directly responsible for the integrating manufacturer's Art.9 compliance. However, component manufacturers face their own Art.9 obligations for the components they integrate. Supply chain compliance is recursive.

The SBOM Obligation

Art.9(1) requires manufacturers to document all third-party components in an SBOM in machine-readable format. This SBOM feeds directly into:

SBOM Format Requirements

CRA Art.9 requires machine-readable format but does not mandate a specific standard. The two dominant formats in practice are:

SPDX (Software Package Data Exchange) — ISO/IEC 5962:2021. Developed under Linux Foundation. Supported natively in many build tools. Recommended by ENISA for CRA compliance. Fields include: package name, version, license, download URL, checksum, and relationship descriptors.

CycloneDX — OWASP standard. JSON, XML, and Protobuf variants. Strong vulnerability management extensions (VEX support). Widely supported in the DevSecOps toolchain. ENISA also acknowledges CycloneDX as a conformant format.

For practical compliance, either format satisfies Art.9. Most organizations adopt the format their toolchain generates automatically (e.g., npm sbom generates SPDX; syft and cdxgen generate CycloneDX).

SBOM Depth Requirements

Art.9 does not specify whether the SBOM must be a shallow manifest (direct dependencies only) or a full transitive closure. ENISA's CRA implementation guidance suggests that a transitive SBOM — covering all dependencies including transitive ones — provides stronger conformity evidence, particularly for supply chain vulnerability management.

In practice, a shallow SBOM satisfies the literal Art.9 requirement; a transitive SBOM is a recommended best practice that reduces audit risk.

The Open Source Component Standard

Art.9(3) creates a specific standard for open source components: reasonable care at the time of integration.

"Reasonable care" is assessed against what a competent developer would do given the available information. In practice, this means:

At integration time:

During the product lifecycle:

The "reasonable care" standard for open source is generally interpreted as lower than the due diligence required for commercial components (where a supplier relationship exists and contractual SLAs can be negotiated). However, it is still a positive obligation — not simply an absence of negligence.

The Open Source Exception (Art.16)

Art.16 carves out obligations for open source software stewards — foundations, non-profit entities, and individuals publishing open source software without commercializing it. Open source stewards face lighter obligations (a "lightweight security policy" rather than full CRA compliance) and are explicitly exempted from certain Art.9 requirements as manufacturers.

This carve-out does not apply to manufacturers who integrate open source components from others. A commercial manufacturer integrating an MIT-licensed library remains fully bound by Art.9. The carve-out applies only to the publishers of that library if they meet the Art.16 steward definition.

Vulnerability Monitoring: Connecting Art.9 and Art.10

Art.9 creates the due diligence process; Art.10 governs what happens when a vulnerability is discovered. The two articles interact continuously:

  1. Art.9 requires maintaining an SBOM and monitoring components for vulnerabilities.
  2. When monitoring surfaces a CVE in an integrated component, Art.9(2) triggers Art.10(1): the manufacturer must "address" the vulnerability.
  3. Art.10 requires the manufacturer to develop and deploy a security update (where technically possible), within a timeframe commensurate with the risk — "without undue delay" for critical vulnerabilities.
  4. If the vulnerability is actively exploited, Art.11 requires notifying ENISA within 24 hours.

The critical design implication: manufacturers must have a process that connects SBOM-based component monitoring to their vulnerability handling workflow. A CVE alert that sits in a dependency scanning dashboard without triggering the Art.10 remediation process is a process failure with regulatory consequence.

Example Integration Flow

CI/CD pipeline:
  → build stage: generate SBOM (cyclonedx-npm / syft)
  → scan stage: check SBOM against OSV.dev / Grype / Snyk
  → if HIGH/CRITICAL CVE found: block build + open security ticket
  → security ticket → triage → patch or accept (with justification)
  → accepted vulnerabilities → VEX document (Art.10 evidence)
  → patched vulnerabilities → update SBOM + new release

This pipeline produces the artifacts needed for Art.9 compliance (SBOM, CVE check evidence) and Art.10 compliance (VEX documents, patch release records).

Practical Tooling

SBOM Generation

ToolLanguage/EcosystemOutput FormatNotes
npm sbomNode.jsSPDX, CycloneDXBuilt into npm ≥9.7
syftMulti (Go, Python, Java, etc.)SPDX, CycloneDXContainer and filesystem scanning
cdxgenMultiCycloneDXStrong Java, Python, Go support
jakePythonCycloneDXWorks with pip/poetry/pipenv
cyclonedx-gomodGoCycloneDXGo module support
trivy sbomContainer imagesSPDX, CycloneDXCombined image SBOM + vulnerability scan

Vulnerability Scanning Against SBOM

ToolFeedsNotes
GrypeNVD, GitHub Advisory, OSVFast, works with SPDX/CycloneDX
OSV-ScannerOSV.devGoogle-maintained, strong open source coverage
SnykSnyk DB (commercial), NVDSaaS with IDE integration
OWASP Dependency-CheckNVDJava-focused, widely used in enterprise
TrivyNVD, GitHub Advisory, OSV, RHSAContainer + filesystem

VEX Document Generation

VEX (Vulnerability Exploitability eXchange) documents are the Art.10 evidence record for known vulnerabilities that have been assessed and accepted. They document:

Tools: vexctl (CycloneDX VEX), parlay (SPDX VEX).

Documentation for the Technical File

Art.9 compliance requires maintaining documentation as part of the technical file (Annex V). At minimum, this includes:

  1. SBOM (machine-readable) — CycloneDX or SPDX, transitive preferred
  2. Vulnerability scan logs — timestamped records of dependency scans run against the current SBOM
  3. Triage records — for each HIGH/CRITICAL finding: accept/patch decision with justification
  4. VEX documents — for accepted known vulnerabilities
  5. Component selection rationale — for significant third-party components, a brief note on why this component was selected and what due diligence was performed at integration time

This documentation does not need to be elaborately formatted — it must be retrievable and accurate. A Git repository containing SBOM JSON files, scan output logs, and a structured markdown decision log satisfies the requirement.

Common Due Diligence Mistakes

1. Static SBOM, no ongoing monitoring. Many manufacturers generate an SBOM at release time but do not update it or re-scan between releases. Art.9 requires ongoing monitoring — a new CVE published against a component you integrated six months ago triggers Art.9(2) obligations today.

2. Transitive dependency blind spot. An application's direct dependencies may be clean while a transitive dependency carries a critical CVE. Shallow SBOMs miss this. Use tools that resolve the full dependency graph.

3. Container base image components omitted. The operating system layers and system libraries in a container image are third-party components for Art.9 purposes. Manufacturers shipping containerized products must include OS-level components in their SBOM and scan them accordingly.

4. Open source components treated as exempt. The Art.16 open source steward exemption does not apply to manufacturers who use open source. The integrating manufacturer remains responsible for due diligence on every open source component they ship.

5. VEX not maintained after initial assessment. A VEX document stating "not affected" for CVE-2024-XXXX is accurate at the time of writing but may become stale if the product changes or new exploit vectors are discovered. VEX documents require periodic review — especially for HIGH/CRITICAL findings.

ObligationArticleRelationship to Art.9
SBOM as part of technical documentationArt.13(12), Annex VArt.9 generates the SBOM; Art.13 requires it in the technical file
Vulnerability handlingArt.10Art.9 monitoring feeds Art.10 remediation process
Reporting actively exploited vulnerabilitiesArt.11If a component CVE is actively exploited, Art.11 24h notification applies
EU Declaration of ConformityArt.28Must cover Art.9 compliance as part of Annex I conformity
Importer obligationsArt.14Importers must verify that manufacturers have met Art.9 obligations before placing products on the market
Open source stewardsArt.16Stewards face lighter obligations; integrators of OSS remain bound by Art.9

Timeline and Deadlines

September 11, 2026 — CRA Art.9 vulnerability reporting obligations (Art.11) begin applying. Manufacturers must have their SBOM-to-vulnerability-monitoring pipeline operational.

December 11, 2027 — Full CRA compliance required. Art.9 due diligence and SBOM documentation must be in place for all products placed on the EU market.

For manufacturers starting today:

Python: CRA Art.9 Due Diligence Checker

import json
from dataclasses import dataclass, field
from typing import Optional
from datetime import datetime, date

@dataclass
class ComponentRecord:
    name: str
    version: str
    source: str  # "commercial" | "open-source"
    sbom_format: Optional[str] = None  # "CycloneDX" | "SPDX" | None
    last_scan_date: Optional[date] = None
    known_cves: list[str] = field(default_factory=list)
    vex_documented: bool = False
    scan_tool: Optional[str] = None

@dataclass
class Art9ComplianceResult:
    component: str
    checks: dict[str, bool]
    gaps: list[str]
    compliant: bool

def check_art9_compliance(components: list[ComponentRecord]) -> list[Art9ComplianceResult]:
    results = []
    today = date.today()
    
    for comp in components:
        checks = {}
        gaps = []
        
        # Check 1: SBOM entry exists (Art.9(1))
        checks["sbom_documented"] = comp.sbom_format is not None
        if not checks["sbom_documented"]:
            gaps.append(f"Component not documented in machine-readable SBOM (Art.9(1))")
        
        # Check 2: Vulnerability scan performed (Art.9(1) + Art.9(3))
        checks["scan_performed"] = comp.last_scan_date is not None
        if not checks["scan_performed"]:
            gaps.append("No vulnerability scan record (Art.9(3) reasonable care)")
        
        # Check 3: Scan not stale (>90 days for ongoing monitoring)
        if comp.last_scan_date:
            days_since_scan = (today - comp.last_scan_date).days
            checks["scan_current"] = days_since_scan <= 90
            if not checks["scan_current"]:
                gaps.append(f"Last scan {days_since_scan} days ago — ongoing monitoring required (Art.9(2))")
        else:
            checks["scan_current"] = False
        
        # Check 4: Known CVEs have VEX documentation (Art.9(2) + Art.10)
        if comp.known_cves:
            checks["cves_addressed"] = comp.vex_documented
            if not checks["cves_addressed"]:
                gaps.append(
                    f"Known CVEs {comp.known_cves} not addressed — "
                    "VEX document or patch required (Art.9(2), Art.10)"
                )
        else:
            checks["cves_addressed"] = True
        
        compliant = all(checks.values())
        results.append(Art9ComplianceResult(
            component=f"{comp.name}@{comp.version}",
            checks=checks,
            gaps=gaps,
            compliant=compliant
        ))
    
    return results

# Example usage
components = [
    ComponentRecord(
        name="lodash",
        version="4.17.21",
        source="open-source",
        sbom_format="CycloneDX",
        last_scan_date=date(2026, 3, 15),
        known_cves=["CVE-2021-23337"],
        vex_documented=True,  # Assessed: not exploitable in this code path
        scan_tool="Grype"
    ),
    ComponentRecord(
        name="openssl",
        version="3.0.7",
        source="open-source",
        sbom_format="SPDX",
        last_scan_date=date(2025, 12, 1),  # stale!
        known_cves=[],
        scan_tool="OSV-Scanner"
    ),
    ComponentRecord(
        name="vendor-sdk",
        version="2.1.0",
        source="commercial",
        sbom_format=None,  # missing SBOM entry
        last_scan_date=None,
        known_cves=["CVE-2025-11111"],
        vex_documented=False
    ),
]

results = check_art9_compliance(components)
for r in results:
    status = "COMPLIANT" if r.compliant else "NON-COMPLIANT"
    print(f"\n{r.component}: {status}")
    for gap in r.gaps:
        print(f"  ⚠ {gap}")

Checklist: CRA Art.9 Due Diligence

Use this checklist for each product with digital elements:

SBOM (Art.9(1))

Vulnerability Monitoring (Art.9(2), Art.9(3))

Open Source Components (Art.9(3))

VEX Documentation (Art.10 connection)

Process Documentation

Conclusion

CRA Art.9 transforms third-party component integration from a development convenience into a documented compliance process. The core obligations — maintain a machine-readable SBOM, monitor integrated components for vulnerabilities, and treat component CVEs as product vulnerabilities — are achievable with modern DevSecOps tooling.

The challenge is operationalizing these checks at scale, especially for products with hundreds of transitive dependencies, and keeping the process running continuously rather than only at release time.

Manufacturers who build SBOM generation and vulnerability scanning into their CI/CD pipeline now, well ahead of the September 2026 and December 2027 deadlines, will enter the compliance period with evidence packages already assembled — rather than scrambling to reconstruct dependency histories retroactively.


This post is part of the sota.io EU Cyber Compliance Series. For related articles, see CRA Art.10: Vulnerability Handling Obligations, CRA Art.11: Reporting Obligations, CRA Art.12: Authorised Representatives, CRA Art.13: Manufacturer Obligations, and CRA Art.8: Open Source Software Stewards.