2026-04-19·20 min read·

CRA Art.6: Essential Requirements (Annex I) — Security-by-Design, No Known Vulnerabilities, Secure Updates (Developer Guide 2026)

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

The EU Cyber Resilience Act (Regulation (EU) 2024/2847, "CRA") entered into force on 10 December 2024. Article 6 is the compliance core of the entire regulation: it mandates that every product with digital elements must satisfy the essential cybersecurity requirements laid out in Annex I.

Article 6 is short — barely a paragraph — but Annex I spans two parts and 20 numbered requirements that define what "secure" means under EU law. These are not aspirational guidelines. They are legally binding conditions for placing any in-scope product on the EU market. Failure to meet them means the product cannot carry the CE mark and cannot be sold in the European Economic Area.

This guide breaks down every requirement in both Parts of Annex I, translates them into concrete engineering decisions, and provides a Python self-assessment tool that scores your product against each requirement.

What Art.6 Actually Says

Article 6 reads, in substance:

Products with digital elements shall be designed, developed and produced in a way that ensures an appropriate level of cybersecurity based on the risks, and shall satisfy the essential cybersecurity requirements set out in Annex I, Part I. Manufacturers shall also satisfy the vulnerability handling requirements set out in Annex I, Part II.

Three things to note immediately:

"Based on the risks" — this is a risk-based standard, not a prescriptive checklist. A children's toy with Bluetooth has different security obligations than an industrial SCADA gateway. Annex I requirements must be implemented proportionate to the risk profile of your product. Recital 34 clarifies that the risk assessment must consider the probability of exploitation, the severity of potential harm, and the affected user base.

"Shall be designed, developed and produced" — the obligation covers the entire product lifecycle from initial architecture through manufacturing. You cannot patch your way into compliance post-launch; the requirements must be baked into the design process.

Two-part structure — Part I covers properties of the product itself (12 requirements). Part II covers how manufacturers handle vulnerabilities throughout the product's supported lifetime (8 requirements). Both are mandatory for all manufacturers.

Annex I, Part I: Product Security Requirements

Requirement 1: No Known Exploitable Vulnerabilities at Market Placement

Products shall be placed on the market without any known exploitable vulnerabilities.

This is the most operationally demanding requirement. "Known" means known to the manufacturer — which creates a due diligence obligation to actively search for vulnerabilities before shipping.

In practice, this means:

The standard is exploitable vulnerabilities, not all vulnerabilities. A theoretical vulnerability with no known exploit vector and documented compensating controls may pass the requirement. Document your reasoning in the technical file.

# Minimal CI gate for R1 compliance
def check_no_known_exploitable_vulns(sbom_file: str) -> bool:
    """Query OSV API for each component in SBOM."""
    import json, requests
    with open(sbom_file) as f:
        sbom = json.load(f)
    
    findings = []
    for component in sbom.get("components", []):
        purl = component.get("purl", "")
        if not purl:
            continue
        resp = requests.post(
            "https://api.osv.dev/v1/query",
            json={"package": {"purl": purl}}
        )
        vulns = resp.json().get("vulns", [])
        if vulns:
            findings.append({
                "component": component.get("name"),
                "vulns": [v["id"] for v in vulns]
            })
    
    if findings:
        print("FAIL — Known vulnerabilities found:")
        for f in findings:
            print(f"  {f['component']}: {', '.join(f['vulns'])}")
        return False
    return True

Requirement 2: Secure by Default Configuration

Products shall be placed on the market with a secure by default configuration.

"Secure by default" has a specific meaning: the product's out-of-the-box configuration must not expose unnecessary attack surface. The exception clause — "unless a specific configuration is required to be decided upon by the user due to the intended purpose" — is narrow and does not cover convenience features.

Concrete implications:

FeatureInsecure Default (Non-Compliant)Secure Default (Compliant)
Admin interfaceAdmin/admin credentialsForced credential setup on first boot
Remote accessSSH/Telnet open on all interfacesDisabled; user must explicitly enable
TelemetryEnabled, opt-outDisabled, opt-in
Debug endpointsAccessible in production buildCompile-time removed or auth-gated
Unused servicesRunningDisabled by default
TLS versionTLS 1.0/1.1 acceptedTLS 1.2+ only; TLS 1.0/1.1 rejected

The Commission's published guidance (CEN/CENELEC standards in preparation) treats default password policies, default service exposure, and default telemetry as the three highest-scrutiny areas.

Requirement 3: Protection Against Unauthorized Access

Products shall ensure protection against unauthorized access by appropriate control mechanisms, including but not limited to authentication, identity or access management systems.

"Appropriate" is again risk-proportionate. For a consumer IoT product, appropriate means: unique per-device credentials, no universal factory passwords, account lockout after failed attempts, and multi-factor authentication for administrative functions.

The key phrase is "including but not limited to authentication" — authorization (what an authenticated user can do) and identity management (lifecycle of credentials and tokens) are also in scope. Broken access control is not just an OWASP Top 10 issue; under the CRA it is a compliance violation.

Access control requirements that map to CRA R3:

Requirement 4: Confidentiality of Data

Products shall protect the confidentiality of stored, transmitted or otherwise processed data, personal or other, such as by encrypting relevant data at rest or in transit by state-of-the-art mechanisms.

The phrase "state-of-the-art mechanisms" incorporates a moving target. As of 2026:

Note that the requirement extends to "personal or other" data — the confidentiality obligation is not limited to personal data covered by GDPR. All sensitive operational data (configuration secrets, proprietary algorithms, user behavioral data) falls within scope.

Requirement 5: Integrity of Data

Products shall protect the integrity of stored, transmitted or otherwise processed data, personal or other, commands, programs and configuration against any manipulation or modification not authorized by the user, as well as report on corruptions.

Integrity is broader than confidentiality — it covers detecting tampering, not just preventing unauthorized reading. The "report on corruptions" clause is significant: passive integrity protection (preventing modification) is necessary but not sufficient; the product must also detect and report when integrity fails.

Engineering implications:

Requirement 6: Data Minimisation

Products shall process only data, personal or other, that are adequate, relevant and limited to what is necessary in relation to the intended purpose of the product.

This imports GDPR's Article 5(1)(c) data minimisation principle directly into product security law. The key word is "process" — data minimisation applies to collection, storage, transmission, and use.

The CRA's data minimisation requirement applies to all data, not just personal data. This has practical implications for telemetry-heavy IoT products: detailed device telemetry sent to vendor clouds must be justified by the intended purpose, not collected as a general intelligence resource.

Implementation checklist:

Requirement 7: Availability of Essential Functions

Products shall protect the availability of essential functions, including the resilience against and mitigation of denial of service attacks.

"Essential functions" means the core purpose of the product. For a network camera, recording and remote viewing are essential. For an industrial sensor, accurate measurement output is essential. DoS resilience must protect these functions even under attack.

Practical implications:

For Class B Important products (firewalls, network management, ICS gateways), the DoS resilience requirements are subject to third-party testing under Annex VII.

Requirement 8: Minimize Impact on Other Devices and Networks

Products shall minimize their own negative impact on the availability of services provided by other devices or networks.

This is a "good neighbour" requirement: your product must not amplify traffic attacks, participate in botnets, or overwhelm shared network resources when compromised or malfunctioning.

Engineering controls that address R8:

Requirement 9: Limit Attack Surface

Products shall be designed, developed and produced to limit attack surfaces, including external interfaces.

Attack surface reduction is an architectural requirement, not a patching strategy. Annex I requires it to be built into the design phase.

The phrase "including external interfaces" specifically targets exposed ports, APIs, and communication protocols as primary attack surface.

Attack surface inventory for a typical IoT product:

InterfaceAttack Surface Reduction
USB/SerialDisable debug interfaces in production firmware
Bluetooth/Wi-FiDisable if not required for intended purpose
HTTP APIHTTPS only; disable HTTP; no directory listing
MQTT brokerTLS required; no anonymous connections
SSH managementKey-based auth only; disable password auth; rate-limit
UART debugRemove or require physical access; no unauthenticated commands
BootloaderSecure boot; disable JTAG in production

Requirement 10: Limit Impact of Incidents

Products shall be designed, developed and produced to reduce the impact of an incident using appropriate exploitation mitigation mechanisms and techniques.

This is the CRA's "assume breach" requirement: products must be designed to contain the blast radius when exploitation occurs.

Exploitation mitigation techniques that apply:

Requirement 11: Security Logging and Monitoring

Products shall provide security-related information by recording and/or monitoring relevant internal activity, including the access to or modification of data, services or functions, with a recording retention policy in mind.

Audit logging is mandatory under the CRA. The requirement specifies both what to log and that a retention policy must exist.

Mandatory security events to log:

The "retention policy in mind" clause means products must either include configurable log retention or document the retention approach in the user documentation. Indefinite retention and zero retention are both non-compliant.

import logging
import json
from datetime import datetime

class CRASecurityAuditLogger:
    """Minimal CRA-compliant security audit logger."""
    
    SECURITY_EVENTS = {
        "AUTH_SUCCESS", "AUTH_FAILURE", "AUTH_LOCKOUT",
        "ACCESS_DENIED", "CONFIG_CHANGE", "FW_UPDATE",
        "CERT_CHANGE", "ADMIN_ACTION", "ANOMALY_DETECTED"
    }
    
    def __init__(self, retention_days: int = 90):
        self.retention_days = retention_days
        self.logger = logging.getLogger("security.audit")
    
    def log(self, event_type: str, subject: str, details: dict):
        if event_type not in self.SECURITY_EVENTS:
            raise ValueError(f"Unknown security event type: {event_type}")
        
        entry = {
            "ts": datetime.utcnow().isoformat() + "Z",
            "event": event_type,
            "subject": subject,
            "retention_days": self.retention_days,
            **details
        }
        self.logger.info(json.dumps(entry))

Requirement 12: Updateability and Security Patches

Products shall ensure that vulnerabilities can be addressed through security updates, including, where applicable, through automatic updates and the notification of available updates to users, with the option to postpone them.

This is one of the most operationally complex requirements. It creates a technical obligation to implement an update mechanism, not just a policy obligation to release patches.

Key elements:

from dataclasses import dataclass
from typing import Optional
import hashlib, hmac

@dataclass  
class SecurityUpdate:
    version: str
    released_at: str
    severity: str  # "critical", "high", "medium", "low"
    cve_ids: list[str]
    description: str
    download_url: str
    signature: str  # Ed25519 signature over version+hash
    
class UpdateManager:
    def __init__(self, public_key: bytes):
        self.public_key = public_key
    
    def verify_update(self, update: SecurityUpdate, package_bytes: bytes) -> bool:
        """Verify update integrity before installation (CRA R5 + R12)."""
        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
        from cryptography.exceptions import InvalidSignature
        import base64
        
        key = Ed25519PublicKey.from_public_bytes(self.public_key)
        pkg_hash = hashlib.sha256(package_bytes).hexdigest()
        payload = f"{update.version}:{pkg_hash}".encode()
        
        try:
            key.verify(base64.b64decode(update.signature), payload)
            return True
        except InvalidSignature:
            return False
    
    def notify_user(self, update: SecurityUpdate, auto_install: bool = False) -> dict:
        """Notify user of available update with postpone option (CRA R12)."""
        return {
            "available_version": update.version,
            "severity": update.severity,
            "cves": update.cve_ids,
            "description": update.description,
            "auto_install_scheduled": auto_install,
            "user_can_postpone": True,  # CRA R12 mandatory
            "postpone_endpoint": "/api/updates/postpone"
        }

Annex I, Part II: Vulnerability Handling Requirements

Part II governs how manufacturers manage vulnerabilities throughout the product's supported lifetime. These are ongoing operational obligations, not one-time design decisions.

VH-1: SBOM and Component Documentation

Manufacturers shall identify and document vulnerabilities and components contained in the product with digital elements, including by drawing up a software bill of materials in a commonly used and machine-readable format covering at the very least the top-level dependencies of the product.

The CRA mandates an SBOM. The format requirement ("commonly used and machine-readable") points to CycloneDX or SPDX, both of which are machine-readable, widely supported, and accepted by EU market surveillance authorities.

The requirement covers "at the very least the top-level dependencies" — this is a floor, not a ceiling. Best practice (and what the Commission's harmonised standards will likely require) is a full transitive dependency SBOM.

# Generate CycloneDX SBOM from Python project
pip install cyclonedx-bom
cyclonedx-py environment --output-format json > sbom.json

# Generate from Node.js project  
npx @cyclonedx/cyclonedx-npm --output-format json > sbom.json

# Validate SBOM
pip install cyclonedx-lib
python -c "from cyclonedx.validation.json import JsonStrictValidator; ..."

VH-2: Address and Remediate Vulnerabilities Without Delay

Manufacturers shall address and remediate vulnerabilities without delay, including by providing security updates.

"Without delay" is not defined numerically in the CRA. The Commission's guidance references industry norms: critical vulnerabilities (CVSS ≥ 9.0) typically within 24-72 hours of patch availability; high vulnerabilities within 7-14 days; medium within 30-60 days.

The CVD policy required by VH-5 should document your remediation SLAs for each severity tier. These become enforceable commitments once published.

VH-3: Regular Testing and Security Reviews

Manufacturers shall apply effective and regular testing and reviews of the security of the product with digital elements.

"Regular" testing must be documented. A minimum viable interpretation:

VH-4: Share Information About Fixed Vulnerabilities

Once a security update has been made available, manufacturers shall share information about fixed vulnerabilities without undue delay, including a description, affected versions, impacts, severity, and remediation guidance.

This is a post-patch disclosure requirement. It creates an obligation to publish a security advisory for every patched vulnerability. The advisory must include:

VH-5: Coordinated Vulnerability Disclosure Policy

Manufacturers shall put in place and enforce a policy on coordinated vulnerability disclosure.

Every in-scope manufacturer must have a published CVD policy. The deadline for all in-scope manufacturers is September 2026. The policy must:

# /.well-known/security.txt (RFC 9116 compliant)
Contact: security@yourcompany.com
Expires: 2027-04-19T00:00:00.000Z
Acknowledgments: https://yourcompany.com/security/hall-of-fame
Policy: https://yourcompany.com/security/cvd-policy
Preferred-Languages: en, de
Encryption: https://yourcompany.com/.well-known/pgp-key.asc

VH-6: Vulnerability Reporting Contact

Manufacturers shall take measures to facilitate sharing of information about potential vulnerabilities, including by providing a contact address.

A public security contact is mandatory. The security.txt contact above satisfies this. The contact must be monitored — an unmonitored email address does not satisfy the requirement.

VH-7: Secure Update Distribution Mechanism

Manufacturers shall provide mechanisms to distribute updates securely.

The update distribution mechanism must itself be secure. This means:

VH-8: Free-of-Charge and Timely Security Patches

Security patches or updates available to address identified security issues shall be disseminated without undue delay, free of charge, and accompanied by advisory messages.

The "free of charge" requirement is absolute. You cannot gate security patches behind a paid subscription tier. Commercial feature updates may be subscription-gated; security patches may not. This has pricing model implications for any product with a freemium or tiered licensing structure.

"Advisory messages" accompanying the update must include the CVE IDs, severity, and what the patch actually does.

Full Self-Assessment Tool

#!/usr/bin/env python3
"""
CRA Annex I Self-Assessment Tool
Scores product against all 20 requirements (12 Part I + 8 Part II)
"""

from dataclasses import dataclass, field
from typing import Optional

@dataclass
class RequirementScore:
    ref: str
    name: str
    score: int  # 0=Not Met, 1=Partial, 2=Met
    notes: str = ""

class CRAannexIAssessment:
    
    REQUIREMENTS = [
        ("I.1", "No known exploitable vulnerabilities at market placement"),
        ("I.2", "Secure by default configuration"),
        ("I.3", "Protection against unauthorized access"),
        ("I.4", "Confidentiality of data (encryption at rest + in transit)"),
        ("I.5", "Integrity of data, commands, configuration"),
        ("I.6", "Data minimisation"),
        ("I.7", "Availability of essential functions (DoS resilience)"),
        ("I.8", "Minimize negative impact on other devices/networks"),
        ("I.9", "Limit attack surface incl. external interfaces"),
        ("I.10", "Limit impact of incidents (exploitation mitigation)"),
        ("I.11", "Security logging with retention policy"),
        ("I.12", "Updateability and security patch mechanism"),
        ("II.1", "SBOM in machine-readable format"),
        ("II.2", "Vulnerability remediation without delay"),
        ("II.3", "Regular testing and security reviews"),
        ("II.4", "Post-patch advisory with CVE, severity, remediation"),
        ("II.5", "Published CVD policy"),
        ("II.6", "Vulnerability reporting contact address"),
        ("II.7", "Secure update distribution mechanism"),
        ("II.8", "Security patches free of charge, with advisories"),
    ]
    
    def __init__(self):
        self.scores: list[RequirementScore] = []
    
    def assess(self, ref: str, score: int, notes: str = ""):
        name = next(n for r, n in self.REQUIREMENTS if r == ref)
        self.scores.append(RequirementScore(ref, name, score, notes))
    
    def report(self) -> dict:
        total = sum(s.score for s in self.scores)
        max_score = len(self.REQUIREMENTS) * 2
        pct = (total / max_score) * 100 if max_score else 0
        
        not_met = [s for s in self.scores if s.score == 0]
        partial = [s for s in self.scores if s.score == 1]
        met = [s for s in self.scores if s.score == 2]
        
        print(f"\n=== CRA Annex I Assessment Report ===")
        print(f"Score: {total}/{max_score} ({pct:.0f}%)")
        print(f"Met: {len(met)} | Partial: {len(partial)} | Not Met: {len(not_met)}")
        
        if not_met:
            print(f"\n❌ NOT MET (immediate action required):")
            for s in not_met:
                print(f"  [{s.ref}] {s.name}")
                if s.notes:
                    print(f"         → {s.notes}")
        
        if partial:
            print(f"\n⚠️  PARTIAL (remediation needed before market placement):")
            for s in partial:
                print(f"  [{s.ref}] {s.name}")
                if s.notes:
                    print(f"         → {s.notes}")
        
        verdict = "COMPLIANT" if not not_met and not partial else \
                  "NON-COMPLIANT — cannot place on EU market"
        print(f"\nVerdict: {verdict}")
        return {"score": total, "max": max_score, "verdict": verdict}


# Example usage
if __name__ == "__main__":
    a = CRAannexIAssessment()
    
    # Score your product: 0=Not Met, 1=Partial, 2=Met
    a.assess("I.1",  2, "OSV scanner in CI, no CVSS≥7 unpatched")
    a.assess("I.2",  2, "Forced credential setup on first boot")
    a.assess("I.3",  1, "Password auth; MFA pending for admin API")
    a.assess("I.4",  2, "TLS 1.3 in transit; AES-256-GCM at rest")
    a.assess("I.5",  1, "Firmware signed; config integrity check missing")
    a.assess("I.6",  1, "Telemetry minimized; retention policy draft")
    a.assess("I.7",  2, "Rate limiting on all public endpoints")
    a.assess("I.8",  2, "Egress rate limiting; exponential backoff")
    a.assess("I.9",  1, "Debug UART disabled in prod; JTAG pending")
    a.assess("I.10", 1, "ASLR/NX enabled; sandboxing not yet implemented")
    a.assess("I.11", 2, "90-day retention; AUTH/ADMIN events logged")
    a.assess("I.12", 2, "Signed OTA; user notification; postpone endpoint")
    a.assess("II.1", 1, "Top-level SBOM exists; transitive pending")
    a.assess("II.2", 2, "SLA: critical=24h, high=7d, medium=30d")
    a.assess("II.3", 1, "SAST in CI; pen test scheduled Q3")
    a.assess("II.4", 0, "No advisory process defined yet")
    a.assess("II.5", 1, "CVD policy draft; security.txt pending")
    a.assess("II.6", 2, "security@company.com monitored 24/7")
    a.assess("II.7", 2, "HTTPS + Ed25519 signatures; downgrade protection")
    a.assess("II.8", 0, "Paid tier required for security updates — MUST FIX")
    
    a.report()

CRA Art.6 Compliance Roadmap

PhaseDeadlineScopeKey Actions
CVD PolicySep 2026All in-scope productsPublish CVD policy, security.txt, monitoring
SBOMSep 2026All in-scope productsGenerate CycloneDX SBOM, integrate into CI
CE MarkingDec 2027Standard productsComplete Annex I compliance, conformity assessment
Class ADec 2027Important productsThird-party conformity assessment (Annex VI/VII)
Class B/CriticalDec 2027Critical productsMandatory notified body certification

What This Means for Hosted Software (SaaS/PaaS)

If you operate a pure SaaS platform excluded from CRA scope under Art.2(3), Annex I does not directly apply to your platform. However:

  1. Embedded agents or clients distributed to users (CLI tools, desktop apps, browser extensions) are in scope as products with digital elements
  2. SDKs you distribute for integrating with your platform are in scope as components
  3. Customer trust: customers building in-scope products on your platform will scrutinize your security practices because their Annex I compliance depends partly on their infrastructure choices

For European PaaS providers like sota.io, Annex I awareness matters because enterprise customers ask about it in vendor security questionnaires.

See Also