EU AI Act Art.15 vs CRA Annex I: Cybersecurity Requirements Overlap and Divergence
Post #2 in the EU AI Act + CRA Dual Compliance Developer Series (5 posts)
Post 1 established who falls under both regulations. This post maps what each demands on cybersecurity specifically — and where you can satisfy both with shared controls vs. where each demands something the other does not.
The short version: Art.15 focuses on the AI model's security properties during its lifecycle. CRA Annex I focuses on the product's security properties across all software components. CRA Art.12 explicitly says these layer, not substitute. Your compliance budget goes furthest when you implement shared controls once and document them against both frameworks simultaneously.
What EU AI Act Art.15 Requires
Art.15 is titled "Accuracy, robustness and cybersecurity." It applies to high-risk AI systems and demands:
Art.15(1): Accuracy levels High-risk AI systems must be designed and developed so that they achieve an appropriate level of accuracy, robustness, and cybersecurity. The appropriate levels and metrics must be declared in the technical documentation (Annex IV).
Art.15(2): Resilience against errors and inconsistencies High-risk AI systems must be resilient to errors, faults, and inconsistencies that may occur within the system or in the environment in which it operates — in particular from:
- Interaction with other systems
- Human errors in operation
- Attempts at manipulation by third parties
Art.15(3): Technical redundancy and fallback solutions Where relevant to product purpose, high-risk AI systems must include technical redundancy solutions, including fallbacks and fail-safe plans. This is a design requirement, not just a monitoring requirement.
Art.15(4): Robustness against adversarial attacks High-risk AI systems accessible via network interfaces must be developed with state-of-the-art cybersecurity measures to prevent unauthorised third parties from accessing, exploiting, or modifying them. This specifically calls out training data poisoning, model evasion, adversarial examples, and model extraction.
Art.15(5): Logging for cybersecurity incidents High-risk AI systems must record relevant cybersecurity-related events detected during operation. These logs feed the Art.12 record-keeping obligations and the Art.73 incident reporting trigger.
from dataclasses import dataclass
from typing import Optional, List
from enum import Enum
import logging
import hashlib
from datetime import datetime
class SecurityEventType(Enum):
ADVERSARIAL_INPUT = "adversarial_input"
MODEL_EXTRACTION_ATTEMPT = "model_extraction_attempt"
DATA_POISONING_DETECTED = "data_poisoning_detected"
AUTHENTICATION_FAILURE = "authentication_failure"
UNAUTHORIZED_ACCESS = "unauthorized_access"
INPUT_ANOMALY = "input_anomaly"
OUTPUT_ANOMALY = "output_anomaly"
@dataclass
class SecurityEvent:
event_type: SecurityEventType
timestamp: datetime
system_id: str
severity: str # critical / high / medium / low
source_ip: Optional[str]
request_hash: Optional[str]
ai_decision_id: Optional[str]
details: str
class ArtFifteenSecurityLogger:
"""
Art.15(5)-compliant security event logger for high-risk AI systems.
Records events required by AI Act and feeds CRA Annex I Part II vulnerability tracking.
"""
def __init__(self, system_id: str, logger: logging.Logger):
self.system_id = system_id
self.logger = logger
def log_security_event(self, event: SecurityEvent) -> str:
"""Log and return event ID for Art.12 record-keeping chain."""
event_id = hashlib.sha256(
f"{event.timestamp.isoformat()}{event.system_id}{event.event_type.value}".encode()
).hexdigest()[:16]
self.logger.warning(
"AI_SECURITY_EVENT",
extra={
"event_id": event_id,
"event_type": event.event_type.value,
"system_id": event.system_id,
"severity": event.severity,
"timestamp": event.timestamp.isoformat(),
"ai_decision_id": event.ai_decision_id,
"details": event.details,
# CRA Annex I Part II: vulnerability tracking fields
"regulatory_frameworks": ["EU_AI_ACT_ART15", "CRA_ANNEX_I_PART_II"],
}
)
return event_id
def detect_adversarial_input(self, input_vector, model_output, confidence: float) -> Optional[SecurityEvent]:
"""
Art.15(4): detect adversarial examples and input manipulation.
Returns SecurityEvent if anomaly detected, None otherwise.
"""
# Low confidence + unusual input pattern = potential adversarial
if confidence < 0.3:
return SecurityEvent(
event_type=SecurityEventType.ADVERSARIAL_INPUT,
timestamp=datetime.utcnow(),
system_id=self.system_id,
severity="high",
source_ip=None,
request_hash=hashlib.sha256(str(input_vector).encode()).hexdigest()[:16],
ai_decision_id=None,
details=f"Low-confidence output ({confidence:.2f}) suggests potential adversarial input"
)
return None
What CRA Annex I Requires
CRA Annex I is split into two parts:
Part I: Security properties of the product (during design and manufacture)
The 13 essential requirements cover:
- No known exploitable vulnerabilities at time of placing on market
- Secure by default configuration
- Protection of data at rest and in transit (authenticity, integrity, confidentiality)
- Protection of data processed by the product against manipulation and unauthorised access
- Minimisation of data collected and processed (data minimisation)
- Protection of confidentiality, integrity and availability of stored, transmitted and processed data
- Ability to limit attack surface (reducing unused features, ports, services)
- Reduced impact of incidents through appropriate isolation mechanisms
- Record-keeping of security-relevant events (logs)
- Ability to perform security updates (the update pipeline obligation)
- Freedom from known exploitable vulnerabilities in third-party components
- Secure configuration by default
- Revocation and invalidation capability for authentication mechanisms
Part II: Vulnerability handling requirements (post-market)
- Identify and document vulnerabilities and components (SBOM — Art.31 + Annex VII)
- Address and remediate vulnerabilities without delay
- Apply effective coordinated vulnerability disclosure (CVD) policy
- Release security updates free of charge within a defined timeframe
- Provide vulnerability information publicly (CVE database)
- Apply a policy for coordinated disclosure
- Provide security contact information (security.txt or equivalent)
from dataclasses import dataclass, field
from typing import List, Dict, Optional
from datetime import datetime, timedelta
from enum import Enum
class VulnerabilitySeverity(Enum):
CRITICAL = "critical" # CVSS 9.0-10.0
HIGH = "high" # CVSS 7.0-8.9
MEDIUM = "medium" # CVSS 4.0-6.9
LOW = "low" # CVSS 0.1-3.9
@dataclass
class VulnerabilityRecord:
"""CRA Annex I Part II: vulnerability tracking record."""
cve_id: Optional[str]
component: str
component_version: str
severity: VulnerabilitySeverity
discovered_at: datetime
cvd_notified_at: Optional[datetime] # coordinated disclosure
patch_available_at: Optional[datetime]
patch_released_at: Optional[datetime]
public_disclosure_at: Optional[datetime]
def days_to_patch(self) -> Optional[int]:
"""CRA Annex I Part II req 2: patch 'without delay'."""
if self.patch_released_at:
return (self.patch_released_at - self.discovered_at).days
return None
def is_overdue(self, severity_deadlines: Dict[VulnerabilitySeverity, int]) -> bool:
"""Check if patch is overdue per severity deadline policy."""
deadline_days = severity_deadlines.get(self.severity)
if deadline_days is None or self.patch_released_at:
return False
return (datetime.utcnow() - self.discovered_at).days > deadline_days
class SBOMManager:
"""
CRA Art.31 + Annex VII: Software Bill of Materials management.
Required for CRA compliance; also feeds AI Act Annex IV technical documentation.
"""
def __init__(self):
self.components: List[Dict] = []
def add_component(self, name: str, version: str, license: str,
supplier: str, purl: Optional[str] = None) -> None:
self.components.append({
"name": name,
"version": version,
"license": license,
"supplier": supplier,
"purl": purl, # Package URL — machine-readable component identifier
"added_at": datetime.utcnow().isoformat(),
})
def export_cyclonedx(self) -> Dict:
"""Export CycloneDX 1.4 format — CRA-preferred SBOM format."""
return {
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"version": 1,
"components": [
{
"type": "library",
"name": c["name"],
"version": c["version"],
"licenses": [{"license": {"id": c["license"]}}],
"supplier": {"name": c["supplier"]},
"purl": c.get("purl"),
}
for c in self.components
],
}
The Overlap: Where Art.15 and Annex I Say the Same Thing
Cybersecurity logging
Both require security event logging:
- AI Act Art.15(5): high-risk AI systems must record cybersecurity-relevant events
- CRA Annex I Part I req 9: products must have capability to record security-relevant data
Shared control: A single structured log pipeline (structured JSON, SIEM-forwarded) satisfies both. Label events with both regulatory references for documentation clarity.
Protection against unauthorised access
- AI Act Art.15(4): protect against unauthorised third-party access, exploitation, and modification via network interfaces
- CRA Annex I Part I req 3–4: protect data confidentiality/integrity, prevent unauthorised access
Shared control: mTLS for service-to-service communication, RBAC for data access, API authentication — document once against both frameworks.
Resilience and fail-safe design
- AI Act Art.15(3): technical redundancy and fallback solutions where relevant
- CRA Annex I Part I req 8: reduce impact of incidents through isolation mechanisms
Shared control: Circuit breakers, graceful degradation, rate limiting, and bulkhead isolation serve both requirements simultaneously.
Attack surface reduction
- AI Act Art.15(2): resilience against manipulation and adversarial attacks
- CRA Annex I Part I req 7: ability to limit attack surface (unused features, ports, services)
Shared control: Containerised deployment with minimal base images, no unnecessary services, network policies limiting model API exposure.
from typing import Protocol, runtime_checkable
@runtime_checkable
class DualComplianceSecurityControl(Protocol):
"""
Protocol for security controls that satisfy both EU AI Act Art.15 and CRA Annex I.
Implement this interface to get dual-framework compliance credit.
"""
def get_art15_coverage(self) -> List[str]:
"""Return list of Art.15 requirements this control satisfies."""
...
def get_cra_annex_i_coverage(self) -> List[str]:
"""Return list of CRA Annex I requirements (by number) this control satisfies."""
...
def log_compliance_evidence(self) -> Dict:
"""
Return structured evidence record for both regulatory frameworks.
Used in technical documentation (AI Act Annex IV + CRA Art.31 Annex VII).
"""
...
class AuthenticationControl:
"""
Authentication system that satisfies:
- Art.15(4): protection against unauthorised access via network interfaces
- CRA Annex I Part I req 3: data access protection
- CRA Annex I Part I req 13: revocation capability
"""
def get_art15_coverage(self) -> List[str]:
return ["Art.15(4) — unauthorised access protection"]
def get_cra_annex_i_coverage(self) -> List[str]:
return ["Annex I Part I req 3 (data access)", "Annex I Part I req 13 (revocation)"]
def log_compliance_evidence(self) -> Dict:
return {
"control": "api_authentication",
"mechanism": "JWT with 1h TTL + refresh token rotation",
"revocation": "token_blocklist_redis",
"frameworks": {
"EU_AI_ACT_ART15": "unauthorised_access_protection",
"CRA_ANNEX_I_PART_I": ["req_3", "req_13"],
},
}
The Divergence: Where Each Demands Something Unique
What Art.15 requires that Annex I does not
Adversarial ML robustness (Art.15(4))
AI Act Art.15(4) specifically calls out adversarial examples, model evasion, training data poisoning, and model extraction as threats requiring mitigation. CRA Annex I is product-level and does not address ML-specific attack vectors.
This means dual-regulated products need:
- Adversarial input detection (anomaly scoring, confidence thresholds)
- Training data provenance and integrity verification
- Model output consistency monitoring (detect model extraction via query pattern analysis)
None of these map to a CRA Annex I requirement — they are purely AI Act obligations.
Accuracy levels and metric documentation (Art.15(1))
High-risk AI systems must declare accuracy metrics in technical documentation. CRA has no equivalent requirement for product accuracy. This is an AI Act-only obligation.
Fallback solutions for AI decision continuity (Art.15(3))
The Art.15(3) requirement for fallback plans specifically addresses the scenario where the AI component fails — the system should degrade gracefully to a non-AI decision path. CRA Annex I req 8 addresses isolation but not the concept of a fallback non-AI path.
What CRA Annex I requires that Art.15 does not
SBOM and component vulnerability tracking (Annex I Part II)
CRA requires a Software Bill of Materials (Annex VII), coordinated vulnerability disclosure, and public CVE reporting. AI Act Annex IV (technical documentation) requires component documentation but does not mandate SBOM format, CVD policy, or CVE publication.
Security update delivery obligation (Annex I Part II req 4)
CRA explicitly requires that security updates be available free of charge for the support period. AI Act has no equivalent obligation — it focuses on monitoring and incident reporting, not mandatory update delivery timelines.
Secure-by-default configuration (Annex I Part I req 2 + 12)
CRA requires products to be configured securely out of the box (no unnecessary features enabled, strong defaults). AI Act does not have a secure-by-default requirement — Art.15 addresses the system's security capabilities, not its default configuration state.
Minimal data processing (Annex I Part I req 5)
CRA requires data minimisation at the product level. AI Act Art.10 addresses training data governance but does not impose a runtime data minimisation requirement equivalent to CRA Annex I req 5.
@dataclass
class DualComplianceGap:
"""Track requirements that don't map between frameworks."""
requirement: str
framework: str # "AI_ACT_ART15" or "CRA_ANNEX_I"
maps_to_other: bool
standalone_control_needed: str
DIVERGENCE_MAP: List[DualComplianceGap] = [
# AI Act-only obligations
DualComplianceGap(
requirement="Art.15(1) — accuracy metrics",
framework="AI_ACT_ART15",
maps_to_other=False,
standalone_control_needed="ModelAccuracyMonitor with metric tracking in technical docs"
),
DualComplianceGap(
requirement="Art.15(4) — adversarial ML robustness",
framework="AI_ACT_ART15",
maps_to_other=False,
standalone_control_needed="AdversarialInputDetector + training data integrity verification"
),
DualComplianceGap(
requirement="Art.15(3) — fallback to non-AI path",
framework="AI_ACT_ART15",
maps_to_other=False,
standalone_control_needed="FallbackDecisionEngine for AI component failure"
),
# CRA-only obligations
DualComplianceGap(
requirement="Annex I Part II — SBOM + CVE publication",
framework="CRA_ANNEX_I",
maps_to_other=False,
standalone_control_needed="SBOMManager + CVD policy + security.txt"
),
DualComplianceGap(
requirement="Annex I Part II req 4 — free security updates",
framework="CRA_ANNEX_I",
maps_to_other=False,
standalone_control_needed="Documented patch SLA + free update delivery pipeline"
),
DualComplianceGap(
requirement="Annex I Part I req 2+12 — secure by default",
framework="CRA_ANNEX_I",
maps_to_other=False,
standalone_control_needed="Hardened default configuration + CIS Benchmark alignment"
),
]
CRA Art.12: The Bridge Article
CRA Art.12 explicitly addresses high-risk AI systems: where a product with digital elements is also a high-risk AI system under the EU AI Act, the CRA's Annex I requirements apply in addition to the AI Act's cybersecurity requirements. They do not replace or substitute each other.
The practical implication: you cannot satisfy CRA Annex I by pointing to AI Act Art.15 compliance documentation, and vice versa. Each framework requires its own evidence trail, even where the underlying technical control is identical.
What CRA Art.12 does allow: where both frameworks require logging, for example, a single log pipeline with dual-framework documentation satisfies both. The evidence documents once, maps twice.
Compliance Documentation Strategy
The most efficient approach is a shared control register that maps each technical control to all regulatory requirements it satisfies:
from typing import Dict, List, Any
class DualComplianceControlRegister:
"""
Single source of truth for technical controls satisfying both
EU AI Act Art.15 and CRA Annex I — documentation strategy for Annex IV + CRA Art.31.
"""
def __init__(self, system_id: str, system_name: str):
self.system_id = system_id
self.system_name = system_name
self.controls: List[Dict[str, Any]] = []
def register_control(
self,
control_id: str,
description: str,
implementation: str,
ai_act_mappings: List[str], # e.g. ["Art.15(4)", "Art.15(5)"]
cra_annex_i_mappings: List[str], # e.g. ["Part I req 3", "Part I req 9"]
evidence_location: str,
) -> None:
self.controls.append({
"control_id": control_id,
"description": description,
"implementation": implementation,
"mappings": {
"EU_AI_ACT": ai_act_mappings,
"CRA_ANNEX_I": cra_annex_i_mappings,
},
"evidence": evidence_location,
})
def export_for_technical_docs(self) -> Dict:
"""Export for AI Act Annex IV technical documentation."""
return {
"system": self.system_name,
"framework": "EU AI Act Art.15 + CRA Annex I",
"controls": self.controls,
}
# Example registration
register = DualComplianceControlRegister("ai-saas-prod", "AutoRecruitAI")
register.register_control(
control_id="SEC-001",
description="Structured security event logging with SIEM forwarding",
implementation="JSON-structured logs via structlog → Loki → Grafana",
ai_act_mappings=["Art.15(5) — cybersecurity event recording"],
cra_annex_i_mappings=["Part I req 9 — security-relevant data recording"],
evidence_location="logs/security_events/*.log + docs/sec-001-compliance.md",
)
register.register_control(
control_id="SEC-002",
description="API authentication with token revocation",
implementation="JWT RS256 + Redis blocklist + 1h TTL",
ai_act_mappings=["Art.15(4) — unauthorised access protection"],
cra_annex_i_mappings=["Part I req 3 — data access protection", "Part I req 13 — revocation"],
evidence_location="src/auth/ + docs/sec-002-compliance.md",
)
register.register_control(
control_id="SEC-003",
description="Adversarial input detection",
implementation="Confidence threshold monitoring + input anomaly scoring",
ai_act_mappings=["Art.15(4) — adversarial attack resilience"],
cra_annex_i_mappings=[], # AI Act-only — no CRA equivalent
evidence_location="src/ml/adversarial_detector.py + docs/sec-003-compliance.md",
)
Timeline Summary
| Requirement | Deadline | Framework |
|---|---|---|
| AI Act Art.15 cybersecurity for high-risk AI | August 2, 2026 | EU AI Act |
| CRA Chapter IV (notified body notifications) | June 11, 2026 | CRA |
| CRA Art.14 reporting obligations (24h/72h/14-day) | September 11, 2026 | CRA |
| CRA full manufacturer obligations incl. Annex I | December 11, 2027 | CRA |
For dual-regulated products, August 2, 2026 is the first hard deadline: AI Act Art.15 compliance must be documented in your Annex IV technical documentation by then. CRA Annex I has until December 2027 for full compliance, but CRA Art.14 incident reporting applies from September 11, 2026 — four months after the AI Act deadline.
Developer Checklist: Art.15 + Annex I Shared Controls
Implement these once, map to both frameworks:
- Structured security event logging (Art.15(5) + Annex I Part I req 9)
- API authentication with revocation capability (Art.15(4) + Annex I Part I req 3, 13)
- mTLS for internal service communication (Art.15(4) + Annex I Part I req 3)
- Circuit breakers and graceful degradation (Art.15(3) + Annex I Part I req 8)
- Minimal attack surface — no unnecessary ports/services (Art.15(2) + Annex I Part I req 7)
- Hardened container images with no known CVEs (Art.15(4) + Annex I Part I req 1)
AI Act-only (Art.15 requires, Annex I does not):
- Accuracy metric tracking and documentation (Art.15(1))
- Adversarial input detection (Art.15(4))
- Training data integrity verification (Art.15(4))
- Fallback/non-AI decision path for AI component failure (Art.15(3))
- Model extraction detection via query pattern analysis (Art.15(4))
CRA-only (Annex I requires, Art.15 does not):
- CycloneDX or SPDX SBOM (Annex I Part II, Annex VII)
- Coordinated vulnerability disclosure (CVD) policy (Annex I Part II)
- CVE publication pipeline (Annex I Part II)
- security.txt with contact information (Annex I Part II req 7)
- Secure-by-default configuration documentation (Annex I Part I req 2, 12)
- Free security update delivery commitment (Annex I Part II req 4)
- Data minimisation at runtime product level (Annex I Part I req 5)
EU-Hosted Infrastructure as a Compliance Simplifier
One factor simplifies both frameworks simultaneously: where your product runs. Art.15(4) specifically addresses threats via network interfaces. CRA Annex I Part I addresses data access and modification. Both frameworks' threat models assume the infrastructure provider is outside your control and potentially subject to foreign jurisdiction access.
When infrastructure runs on EU-native hosting (like sota.io on Hetzner Germany) with no US-parent exposure, you remove an entire class of threats from your Art.15(4) and Annex I threat model: covert foreign government access via CLOUD Act-style requests to your cloud provider. This simplifies your compliance documentation for both frameworks — the threat is eliminated at the infrastructure layer, not mitigated by additional controls.
Post 3 covers the incident reporting layer: CRA Art.14 reporting obligations versus AI Act Art.73 incident reporting — and how to build a unified incident pipeline that satisfies both.
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.