DORA Art.13: Learning and Evolving — Post-Incident Reviews, Lessons Learned, ICT Risk Framework Updates, and Security Awareness for Financial Services (2026)
Post #406 in the sota.io EU Cyber Compliance Series
DORA Chapter II defines a six-domain ICT risk management framework. Article 13 closes the loop: where Art.10 requires detection, Art.11 requires response, and Art.12 requires backup recovery, Art.13 mandates that financial entities learn from what happened — formalising the feedback cycle from ICT incidents, threat intelligence, and testing back into the risk management framework itself.
The regulatory logic is explicit: a financial entity that recovers from an incident but does not update its defences, document lessons, or train its staff has not achieved digital operational resilience. It has merely survived. Art.13 operationalises the distinction between survival and learning.
This guide covers all five substantive Art.13 obligations, explains the post-incident review process that satisfies NCA audit requirements, provides a Python self-assessment tool (DORALearningEvolvingChecker), maps to NIS2 Art.21(2) for dual-regulated entities, and closes with a 25-item NCA audit checklist.
1. Who Is Subject to DORA Art.13
DORA Art.2(1) scope covers approximately 22,000 EU financial entities:
| Category | Examples |
|---|---|
| Credit institutions | Banks, savings banks, credit unions |
| Investment firms | Brokers, asset managers, trading firms |
| Insurance/reinsurance | All Art.2(1)(c) undertakings |
| Payment institutions | PSPs, e-money issuers |
| Crypto-asset service providers | CASPs under MiCA |
| Central counterparties | CCPs, CSDs |
| ICT third-party service providers | Cloud, SaaS providers in scope via Art.30 |
Micro-enterprises (fewer than 10 employees, annual turnover ≤ €2 million) may apply a simplified ICT risk management framework under Art.16, but Art.13 obligations apply to all entities regardless of size — the intensity of implementation scales with proportionality (Art.4), not the existence of the obligation.
2. The Five Art.13 Obligations at a Glance
Art.13 imposes five distinct requirements with separate audit evidence trails:
| Paragraph | Obligation | Evidence Required |
|---|---|---|
| Art.13(1) | Gather threat intelligence; analyse impact on digital operational resilience | Threat intel subscription evidence, analysis reports |
| Art.13(2) | Conduct post-incident reviews after major ICT incidents | RCA reports with root cause, impact, corrective actions |
| Art.13(3) | Update ICT risk management framework at least annually or after significant changes | Framework revision history, management sign-off |
| Art.13(4) | ICT security awareness programs and digital operational resilience training | Training records, completion rates, management body participation |
| Art.13(5) | Draw lessons from peers and sector-wide ICT incidents and testing | Information sharing participation evidence, TLPT feedback integration |
3. Art.13(1): Threat Intelligence Gathering and Analysis
Art.13(1) requires financial entities to maintain capabilities and staff to:
- Gather information on vulnerabilities and cyber threats
- Gather information on ICT-related incidents, in particular cyber attacks
- Analyse the impact those could have on their digital operational resilience
3.1 Threat Intelligence Sources
A compliant threat intelligence program must integrate multiple source tiers:
THREAT INTELLIGENCE ARCHITECTURE (Art.13(1) Evidence)
Tier 1 — Strategic Intelligence (Management + Board level)
├── ENISA Threat Landscape (annual, sector reports)
├── ECB Cyber Resilience Oversight Expectations (CROE)
├── EBA/ESMA/EIOPA sector-specific threat publications
└── National CSIRT advisories (CERT-DE, CERT-FR, NCSC-UK, etc.)
Tier 2 — Operational Intelligence (ICT Risk Function)
├── MITRE ATT&CK Financial Services profile updates
├── FS-ISAC (Financial Services Information Sharing and Analysis Center)
├── Sector peer sharing (TIBER-EU intelligence packages)
└── Commercial threat feeds (OSINT + premium) with CVE/NVD correlation
Tier 3 — Technical Intelligence (SOC / Security Engineering)
├── CVE/NVD vulnerability feeds (≤24h SLA for critical)
├── Vendor security advisories (patching SLA per criticality tier)
├── Dark web monitoring (credential exposure, sector targeting)
└── Internal SIEM threat indicators (Art.10 feedback loop)
3.2 Impact Analysis Requirements
Gathering intelligence is necessary but not sufficient — Art.13(1) requires financial entities to analyse the impact on their digital operational resilience. This means:
- Asset mapping: Each threat must be evaluated against the ICT asset inventory (Art.8(1))
- Business function exposure: Impact analysis links threats to critical or important business functions (Art.8(2))
- Dependency chain analysis: Third-party ICT service providers in scope via Art.30 must be included in impact assessments
- Escalation criteria: Threats meeting defined severity thresholds trigger management body notification (Art.5(2))
4. Art.13(2): Post-Incident Reviews After Major ICT Incidents
Art.13(2) is the core learning obligation: after every major ICT-related incident (classification per Art.18(1)), financial entities must conduct a post-incident review to determine:
- Root causes of the incident
- Effectiveness of the incident response
- Lessons learned and corrective actions required
4.1 The 5-Phase Post-Incident Review Process
NCA expectations for post-incident review documentation align with industry standard root cause analysis practices. A compliant process covers five phases:
POST-INCIDENT REVIEW PROCESS (Art.13(2) Evidence Framework)
Phase 1 — Incident Timeline Reconstruction (Days 1-3 post-resolution)
├── Timeline: First detection → Containment → Recovery → Closure
├── Evidence preservation: Log archives, ticket trails, change records
├── Stakeholder interviews: SOC, ICT operations, business function owners
└── Output: Verified chronological event log (immutable, signed)
Phase 2 — Root Cause Analysis (Days 3-10)
├── Technique: 5-Whys + Fishbone (Ishikawa) for complex incidents
├── Categories: Technical (CVE/misconfiguration), Process (gaps/failures),
│ Human (training/awareness), Third-party (vendor/supplier)
├── Contributing factors: Distinguish root cause from proximate causes
└── Output: Root cause statement with evidence chain
Phase 3 — Impact Assessment (Concurrent with Phase 2)
├── Service disruption duration × affected business functions
├── Data exposure/loss: Classification, volume, affected data subjects
├── Financial impact: Direct losses, recovery costs, regulatory fines risk
├── Reputational impact: Client notifications, press coverage, regulator contact
└── Output: Quantified impact report (feeds Art.19 classification review)
Phase 4 — Corrective Action Planning (Days 10-20)
├── Immediate fixes: Patch, configuration change, access revocation
├── Short-term controls: Enhanced monitoring, temporary compensating controls
├── Long-term systemic changes: Framework updates (Art.13(3) trigger)
├── Owner assignment: Named responsible party per action
└── Output: Corrective action plan (CAP) with SMART milestones
Phase 5 — Lessons Learned Dissemination (Days 20-30)
├── Internal: ICT risk function, management body, business function owners
├── Framework integration: CAP items that modify the ICTRMF → Art.13(3)
├── Training updates: Incidents revealing training gaps → Art.13(4) update
├── Peer sharing: Anonymised lessons to FS-ISAC / sector bodies (Art.13(5))
└── Output: Lessons learned report (signed by management body)
4.2 Review Timing Requirements
Art.13(2) does not specify an explicit deadline, but NCA supervisory expectations (aligned with EBA/ESMA supervisory convergence tools) consistently expect:
| Review Component | Expected Timeline |
|---|---|
| Preliminary incident report | 72 hours post-resolution |
| Full root cause analysis | 30 days post-resolution |
| Corrective action plan | 45 days post-resolution |
| Lessons learned report (management sign-off) | 60 days post-resolution |
| CAP implementation verification | Per-action milestone dates |
4.3 Third-Party Incident Reviews
When a major ICT incident involves a third-party ICT service provider, Art.13(2) requires that provider's cooperation in the review process. This obligation should be embedded in ICT service contracts (Art.30 requirements):
CONTRACT CLAUSE (Art.30 + Art.13(2) alignment):
"Following any ICT-related incident classified as 'major' under DORA Art.18(1)
affecting services provided to [Financial Entity], the ICT third-party service
provider shall:
(a) provide full incident timeline data within 5 business days of request;
(b) participate in joint root cause analysis sessions within 15 business days;
(c) deliver a written root cause report within 30 business days;
(d) implement agreed corrective actions within timelines agreed with [Financial Entity];
(e) provide written evidence of corrective action completion."
5. Art.13(3): Updating the ICT Risk Management Framework
Art.13(3) mandates that financial entities update their ICT risk management framework at least:
- Annually (scheduled review)
- After major ICT-related incidents (incident-triggered review)
- Following supervisory instructions (regulatory-triggered review)
- After conclusions from digital operational resilience testing (testing-triggered review)
5.1 Framework Update Cadence
ICTRMF UPDATE CADENCE (Art.13(3) Evidence)
Annual Scheduled Review (Q4 each year)
├── Trigger: Calendar-based (fixed date, management body agenda item)
├── Scope: Full framework review — all six DORA Chapter II domains
├── Input: Threat landscape changes (Art.13(1)), incident history (Art.13(2)),
│ testing results (Art.25/Art.26/Art.27), regulatory updates
├── Process: ICT risk function draft → Management body review → Sign-off
└── Output: Framework revision document (versioned, dated, signed)
Incident-Triggered Update (within 60 days of major incident)
├── Trigger: Post-incident RCA identifies systemic framework gap
├── Scope: Targeted — only affected framework domains
├── Input: Corrective Action Plan (Phase 4 output from Art.13(2) process)
├── Process: Expedited — ICT risk function + management body approval
└── Output: Framework amendment record (references incident RCA)
Supervisory-Triggered Update (per regulatory timeline)
├── Trigger: NCA supervisory assessment, on-site inspection finding
├── Scope: Per supervisory instruction scope
├── Input: Supervisory findings, peer review outcomes
├── Process: Remediation plan + evidence of implementation
└── Output: Supervisory response documentation
Testing-Triggered Update (after each TLPT cycle)
├── Trigger: Threat-Led Penetration Test (Art.26) completion
├── Scope: Targeted — areas where TLPT identified gaps
├── Input: TLPT remediation plan (Art.26(7))
├── Process: Gap closure + framework update within TLPT remediation timeline
└── Output: TLPT remediation evidence + framework update record
5.2 Framework Versioning Requirements
A version-controlled ICT risk management framework is a practical NCA audit requirement. Each version must record:
| Field | Content |
|---|---|
| Version number | Semantic (e.g., v2.3.1) |
| Effective date | When the version takes effect |
| Review type | Annual / Incident / Supervisory / Testing |
| Triggering event | Incident reference / Supervisory finding ref / TLPT ref |
| Changes summary | Delta from previous version (section-level) |
| Approver | Management body sign-off (name, role, date) |
| Next review date | Scheduled next review |
6. Art.13(4): ICT Security Awareness and Digital Operational Resilience Training
Art.13(4) requires financial entities to conduct regular ICT security awareness programs and digital operational resilience training. Key requirements:
6.1 Mandatory Program Components
TRAINING PROGRAM REQUIREMENTS (Art.13(4) Evidence)
All Staff Training (Annual minimum)
├── ICT security awareness: Phishing, social engineering, credential hygiene
├── Incident reporting: How to report suspected incidents (Art.17 procedures)
├── Data handling: Classification, access control, third-party sharing
└── Format: E-learning + annual attestation (completion records mandatory)
Role-Based Training (Risk-proportionate frequency)
├── ICT operations staff: Technical resilience, change management, backup testing
├── Business function owners: BCP activation, RTO/RPO responsibilities
├── Incident response team: Tabletop exercises, playbook rehearsals (≥annual)
└── Third-party contract managers: DORA Art.30 supply chain risk awareness
Management Body Training (Mandatory under Art.5(3))
├── Cybersecurity risk fundamentals (not just IT — systemic risk framing)
├── DORA obligations: Chapter II, Art.17-23 (incident reporting), Art.24-27 (TLPT)
├── Digital operational resilience strategy (Art.6(8))
└── Format: Dedicated session ≥ annually + briefings after major incidents
Specialist Training (Role-specific certification track)
├── CISO / ICT risk function: DORA regulatory updates, NCA supervisory priorities
├── SOC analysts: Threat intelligence analysis, incident classification (Art.18)
├── Pen test / TLPT participants: TIBER-EU framework, Art.26 requirements
└── Procurement: Third-party ICT risk assessment (Art.28-30 obligations)
6.2 Training Records (NCA Audit Evidence)
Art.13(4) does not specify a retention period, but cross-referencing Art.6(8) (ICT risk management framework documentation) and DORA's general supervisory access requirements suggests a minimum 5-year retention for training records:
| Record Type | Minimum Content | Retention |
|---|---|---|
| Completion certificate | Staff ID, course name, completion date, score (if applicable) | 5 years |
| Attendance register | Session date, facilitator, attendee list (signed) | 5 years |
| Training plan | Annual plan, roles covered, frequency, format | 5 years |
| Management body attestation | Individual sign-off on completion | 5 years |
| Incident-triggered training | Reference to triggering incident, updated content | 7 years (matches incident records) |
7. Art.13(5): Drawing Lessons from Peer and Sector-Wide Experience
Art.13(5) requires financial entities to draw lessons from:
- Peer institutions: Incidents at comparable financial entities
- Sector-wide experiences: Industry-level threat intelligence and incident patterns
- Digital operational resilience testing: Own and sector testing outcomes
7.1 Information Sharing Participation
DORA Art.45 explicitly encourages financial entities to participate in voluntary information sharing arrangements. Art.13(5) creates a learning obligation that implicitly requires access to such information — meaning participation in sharing arrangements is a practical compliance requirement:
| Forum | Type | Relevance |
|---|---|---|
| FS-ISAC | Global financial sector ISAC | Incident patterns, threat intelligence |
| TIBER-EU / TLPT programs | National TIBER programs | TLPT intelligence packages |
| ECB cyber resilience forums | EU banking sector | Supervisory intelligence sharing |
| National CSIRT sector sharing | Country-level | National threat actor activity |
| EBA/ESMA/EIOPA supervisory convergence | Regulatory | Cross-sector incident learning |
7.2 Integrating Sector Lessons into the ICTRMF
For sector-level learning to satisfy Art.13(5), it must be documented as input to the framework update process (Art.13(3)):
SECTOR LEARNING INTEGRATION (Art.13(3) + Art.13(5) linkage)
Input: Sector incident report / threat intelligence bulletin
↓
Analysis: Does this incident pattern apply to our ICT asset inventory?
├── Yes → Gap assessment: Does our ICTRMF address this attack vector?
│ ├── Gap identified → Corrective action → Art.13(3) targeted update
│ └── No gap → Document: "Assessed, not applicable, rationale: [reason]"
└── No → Document: "Assessed, not applicable, rationale: [reason]"
↓
Output: Threat assessment memo (filed in ICTRMF documentation)
↓
Periodic review: Sector learning register (annual summary for management body)
8. Python Implementation: DORALearningEvolvingChecker
"""
DORALearningEvolvingChecker — DORA Article 13 Compliance Self-Assessment Tool
Evaluates an organisation's learning and evolving capabilities against
all five Art.13 obligations. Designed for ICT risk functions conducting
internal gap assessments prior to NCA supervisory review.
Usage:
checker = DORALearningEvolvingChecker(entity_config)
report = checker.run_full_assessment()
print(report.to_markdown())
"""
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from datetime import date, timedelta
from typing import Optional
class ComplianceStatus(Enum):
COMPLIANT = "COMPLIANT"
PARTIAL = "PARTIAL"
NON_COMPLIANT = "NON_COMPLIANT"
NOT_ASSESSED = "NOT_ASSESSED"
class ThreatIntelTier(Enum):
STRATEGIC = "strategic" # Board/management level
OPERATIONAL = "operational" # ICT risk function
TECHNICAL = "technical" # SOC/engineering
class IncidentSeverity(Enum):
MAJOR = "major" # Art.18(1) — reportable, Art.13(2) review required
SIGNIFICANT = "significant" # Internal threshold — review recommended
MINOR = "minor" # No mandatory review
@dataclass
class ThreatIntelSource:
name: str
tier: ThreatIntelTier
update_frequency_days: int
last_reviewed: Optional[date] = None
feeds_into_framework: bool = False
@property
def is_stale(self) -> bool:
if self.last_reviewed is None:
return True
return (date.today() - self.last_reviewed).days > self.update_frequency_days
@dataclass
class PostIncidentReview:
incident_id: str
incident_date: date
severity: IncidentSeverity
resolution_date: Optional[date] = None
rca_completed: bool = False
rca_completion_date: Optional[date] = None
corrective_action_plan: bool = False
cap_completion_date: Optional[date] = None
lessons_learned_report: bool = False
ll_sign_off_date: Optional[date] = None
framework_update_triggered: bool = False
third_party_involved: bool = False
third_party_cooperation_documented: bool = False
@property
def days_since_resolution(self) -> Optional[int]:
if self.resolution_date is None:
return None
return (date.today() - self.resolution_date).days
def check_timeliness(self) -> dict[str, ComplianceStatus]:
results = {}
if self.resolution_date is None:
return {"all": ComplianceStatus.NOT_ASSESSED}
days = self.days_since_resolution
# RCA: expected within 30 days
if self.rca_completed and self.rca_completion_date:
rca_days = (self.rca_completion_date - self.resolution_date).days
results["rca_timeliness"] = (
ComplianceStatus.COMPLIANT if rca_days <= 30
else ComplianceStatus.NON_COMPLIANT
)
elif days and days > 30 and not self.rca_completed:
results["rca_timeliness"] = ComplianceStatus.NON_COMPLIANT
else:
results["rca_timeliness"] = ComplianceStatus.NOT_ASSESSED
# CAP: expected within 45 days
if self.corrective_action_plan and self.cap_completion_date:
cap_days = (self.cap_completion_date - self.resolution_date).days
results["cap_timeliness"] = (
ComplianceStatus.COMPLIANT if cap_days <= 45
else ComplianceStatus.NON_COMPLIANT
)
elif days and days > 45 and not self.corrective_action_plan:
results["cap_timeliness"] = ComplianceStatus.NON_COMPLIANT
else:
results["cap_timeliness"] = ComplianceStatus.NOT_ASSESSED
# Lessons learned: expected within 60 days
if self.lessons_learned_report and self.ll_sign_off_date:
ll_days = (self.ll_sign_off_date - self.resolution_date).days
results["ll_timeliness"] = (
ComplianceStatus.COMPLIANT if ll_days <= 60
else ComplianceStatus.NON_COMPLIANT
)
elif days and days > 60 and not self.lessons_learned_report:
results["ll_timeliness"] = ComplianceStatus.NON_COMPLIANT
else:
results["ll_timeliness"] = ComplianceStatus.NOT_ASSESSED
return results
@dataclass
class FrameworkRevision:
version: str
effective_date: date
review_type: str # "annual" | "incident" | "supervisory" | "testing"
triggering_event: Optional[str] = None
management_sign_off: bool = False
next_review_date: Optional[date] = None
@dataclass
class TrainingRecord:
program_name: str
target_audience: str # "all_staff" | "management_body" | "ict_ops" | "specialist"
last_completed: Optional[date] = None
completion_rate_pct: float = 0.0
management_body_included: bool = False
frequency_days: int = 365
@property
def is_overdue(self) -> bool:
if self.last_completed is None:
return True
return (date.today() - self.last_completed).days > self.frequency_days
@dataclass
class EntityConfig:
entity_name: str
threat_intel_sources: list[ThreatIntelSource] = field(default_factory=list)
post_incident_reviews: list[PostIncidentReview] = field(default_factory=list)
framework_revisions: list[FrameworkRevision] = field(default_factory=list)
training_records: list[TrainingRecord] = field(default_factory=list)
isac_membership: bool = False
sector_learning_register_maintained: bool = False
@dataclass
class AssessmentResult:
article: str
obligation: str
status: ComplianceStatus
findings: list[str] = field(default_factory=list)
evidence_items: list[str] = field(default_factory=list)
remediation: list[str] = field(default_factory=list)
class DORALearningEvolvingChecker:
"""DORA Art.13 compliance checker — all five obligations."""
TARGET_ARTICLES = [
"Art.13(1): Threat Intelligence",
"Art.13(2): Post-Incident Reviews",
"Art.13(3): Framework Updates",
"Art.13(4): Security Awareness Training",
"Art.13(5): Sector Learning",
]
def __init__(self, config: EntityConfig):
self.config = config
def check_threat_intelligence(self) -> AssessmentResult:
"""Art.13(1): Validate threat intelligence gathering and analysis."""
findings, evidence, remediation = [], [], []
tiers_covered = {source.tier for source in self.config.threat_intel_sources}
required_tiers = {ThreatIntelTier.STRATEGIC, ThreatIntelTier.OPERATIONAL, ThreatIntelTier.TECHNICAL}
missing_tiers = required_tiers - tiers_covered
if missing_tiers:
findings.append(f"Missing threat intel coverage for tiers: {[t.value for t in missing_tiers]}")
remediation.append("Add threat intelligence sources for each missing tier")
else:
evidence.append(f"All three threat intelligence tiers covered ({len(self.config.threat_intel_sources)} sources)")
stale_sources = [s for s in self.config.threat_intel_sources if s.is_stale]
if stale_sources:
findings.append(f"{len(stale_sources)} threat intel sources not reviewed within frequency window")
remediation.append("Establish regular threat intel review cadence per source frequency")
feeds_framework = [s for s in self.config.threat_intel_sources if s.feeds_into_framework]
if not feeds_framework:
findings.append("No threat intel sources documented as feeding into ICT risk management framework")
remediation.append("Establish documented process linking threat intel analysis to Art.13(3) framework updates")
else:
evidence.append(f"{len(feeds_framework)} sources feed into ICTRMF update process")
status = (
ComplianceStatus.COMPLIANT if not findings
else ComplianceStatus.PARTIAL if len(findings) <= 1
else ComplianceStatus.NON_COMPLIANT
)
return AssessmentResult("Art.13(1)", "Threat Intelligence", status, findings, evidence, remediation)
def check_post_incident_reviews(self) -> AssessmentResult:
"""Art.13(2): Validate post-incident review completeness and timeliness."""
findings, evidence, remediation = [], [], []
major_incidents = [
r for r in self.config.post_incident_reviews
if r.severity == IncidentSeverity.MAJOR
]
if not major_incidents:
evidence.append("No major ICT incidents recorded — no Art.13(2) review obligation triggered")
return AssessmentResult("Art.13(2)", "Post-Incident Reviews",
ComplianceStatus.COMPLIANT, [], evidence, [])
for review in major_incidents:
timeliness = review.check_timeliness()
if not review.rca_completed:
findings.append(f"Incident {review.incident_id}: RCA not completed")
remediation.append(f"Complete root cause analysis for incident {review.incident_id}")
elif timeliness.get("rca_timeliness") == ComplianceStatus.NON_COMPLIANT:
findings.append(f"Incident {review.incident_id}: RCA completed after 30-day window")
if not review.corrective_action_plan:
findings.append(f"Incident {review.incident_id}: Corrective Action Plan missing")
remediation.append(f"Develop CAP with SMART milestones for incident {review.incident_id}")
if not review.lessons_learned_report:
findings.append(f"Incident {review.incident_id}: Lessons Learned Report missing")
remediation.append(f"Complete Lessons Learned Report for incident {review.incident_id}")
if review.third_party_involved and not review.third_party_cooperation_documented:
findings.append(f"Incident {review.incident_id}: Third-party involved but cooperation not documented")
remediation.append("Document third-party cooperation per Art.13(2) requirement")
if review.rca_completed and review.corrective_action_plan and review.lessons_learned_report:
evidence.append(f"Incident {review.incident_id}: Full review completed (RCA + CAP + LL)")
status = (
ComplianceStatus.COMPLIANT if not findings
else ComplianceStatus.PARTIAL if len(findings) <= len(major_incidents)
else ComplianceStatus.NON_COMPLIANT
)
return AssessmentResult("Art.13(2)", "Post-Incident Reviews", status, findings, evidence, remediation)
def check_framework_updates(self) -> AssessmentResult:
"""Art.13(3): Validate ICT risk management framework update cadence."""
findings, evidence, remediation = [], [], []
if not self.config.framework_revisions:
findings.append("No ICT risk management framework revisions documented")
remediation.append("Establish ICTRMF versioning with annual review cycle and management sign-off")
return AssessmentResult("Art.13(3)", "Framework Updates",
ComplianceStatus.NON_COMPLIANT, findings, evidence, remediation)
latest = max(self.config.framework_revisions, key=lambda r: r.effective_date)
days_since_update = (date.today() - latest.effective_date).days
if days_since_update > 365:
findings.append(f"ICTRMF last updated {days_since_update} days ago — exceeds annual review requirement")
remediation.append("Schedule immediate annual ICTRMF review with management body sign-off")
else:
evidence.append(f"ICTRMF updated {days_since_update} days ago (version {latest.version})")
unsigned = [r for r in self.config.framework_revisions if not r.management_sign_off]
if unsigned:
findings.append(f"{len(unsigned)} framework revisions lack management body sign-off")
remediation.append("Obtain retroactive management body sign-off or document approval evidence")
annual_reviews = [r for r in self.config.framework_revisions if r.review_type == "annual"]
if not annual_reviews:
findings.append("No annual scheduled reviews documented — only incident/other triggered updates")
remediation.append("Establish dedicated annual review as separate scheduled process")
else:
evidence.append(f"{len(annual_reviews)} annual reviews documented in revision history")
status = (
ComplianceStatus.COMPLIANT if not findings
else ComplianceStatus.PARTIAL if len(findings) <= 1
else ComplianceStatus.NON_COMPLIANT
)
return AssessmentResult("Art.13(3)", "Framework Updates", status, findings, evidence, remediation)
def check_security_awareness_training(self) -> AssessmentResult:
"""Art.13(4): Validate ICT security awareness and resilience training programs."""
findings, evidence, remediation = [], [], []
if not self.config.training_records:
findings.append("No ICT security awareness training records documented")
remediation.append("Implement annual security awareness program with completion tracking")
return AssessmentResult("Art.13(4)", "Security Awareness Training",
ComplianceStatus.NON_COMPLIANT, findings, evidence, remediation)
all_staff = [t for t in self.config.training_records if t.target_audience == "all_staff"]
if not all_staff:
findings.append("No all-staff ICT security awareness training program found")
remediation.append("Implement mandatory annual all-staff security awareness training")
else:
overdue = [t for t in all_staff if t.is_overdue]
if overdue:
findings.append(f"{len(overdue)} all-staff training programs overdue")
remediation.append("Reschedule overdue training programs immediately")
low_completion = [t for t in all_staff if t.completion_rate_pct < 90.0]
if low_completion:
findings.append(f"{len(low_completion)} training programs below 90% completion rate")
remediation.append("Escalate non-completion to business function managers; consider mandatory completion policy")
else:
evidence.append(f"All-staff training completion rate ≥ 90% across {len(all_staff)} programs")
mgmt_training = [t for t in self.config.training_records if t.target_audience == "management_body"]
if not mgmt_training:
findings.append("No management body ICT security training documented (Art.5(3) + Art.13(4))")
remediation.append("Implement mandatory annual management body cybersecurity training session")
else:
mgmt_incomplete = [t for t in mgmt_training if not t.management_body_included]
if mgmt_incomplete:
findings.append("Management body training records lack individual completion attestation")
remediation.append("Collect signed attestations from each management body member")
else:
evidence.append("Management body training with individual attestation documented")
status = (
ComplianceStatus.COMPLIANT if not findings
else ComplianceStatus.PARTIAL if len(findings) <= 2
else ComplianceStatus.NON_COMPLIANT
)
return AssessmentResult("Art.13(4)", "Security Awareness Training", status, findings, evidence, remediation)
def check_sector_learning(self) -> AssessmentResult:
"""Art.13(5): Validate sector-wide learning and information sharing."""
findings, evidence, remediation = [], [], []
if not self.config.isac_membership:
findings.append("No FS-ISAC or equivalent sector information sharing membership")
remediation.append("Join FS-ISAC or national financial sector ISAC; document participation as Art.13(5) evidence")
else:
evidence.append("FS-ISAC / sector ISAC membership active")
if not self.config.sector_learning_register_maintained:
findings.append("No sector learning register maintained — cannot evidence Art.13(5) compliance")
remediation.append("Implement sector learning register: log each sector threat bulletin reviewed + action taken")
else:
evidence.append("Sector learning register maintained with review and action documentation")
status = (
ComplianceStatus.COMPLIANT if not findings
else ComplianceStatus.PARTIAL if len(findings) == 1
else ComplianceStatus.NON_COMPLIANT
)
return AssessmentResult("Art.13(5)", "Sector Learning", status, findings, evidence, remediation)
def run_full_assessment(self) -> "AssessmentReport":
results = [
self.check_threat_intelligence(),
self.check_post_incident_reviews(),
self.check_framework_updates(),
self.check_security_awareness_training(),
self.check_sector_learning(),
]
return AssessmentReport(entity=self.config.entity_name, results=results)
@dataclass
class AssessmentReport:
entity: str
results: list[AssessmentResult]
def summary(self) -> dict:
counts = {s: 0 for s in ComplianceStatus}
for r in self.results:
counts[r.status] += 1
return {
"entity": self.entity,
"total_checks": len(self.results),
"compliant": counts[ComplianceStatus.COMPLIANT],
"partial": counts[ComplianceStatus.PARTIAL],
"non_compliant": counts[ComplianceStatus.NON_COMPLIANT],
"overall_status": (
"COMPLIANT" if counts[ComplianceStatus.NON_COMPLIANT] == 0 and counts[ComplianceStatus.PARTIAL] == 0
else "PARTIAL" if counts[ComplianceStatus.NON_COMPLIANT] == 0
else "NON_COMPLIANT"
)
}
def to_markdown(self) -> str:
lines = [f"# DORA Art.13 Assessment: {self.entity}\n"]
for r in self.results:
icon = {"COMPLIANT": "✅", "PARTIAL": "⚠️", "NON_COMPLIANT": "❌", "NOT_ASSESSED": "⬜"}
lines.append(f"## {icon.get(r.status.value, '?')} {r.article} — {r.obligation}: {r.status.value}")
if r.findings:
lines.append("**Findings:**")
for f in r.findings:
lines.append(f"- {f}")
if r.evidence_items:
lines.append("**Evidence:**")
for e in r.evidence_items:
lines.append(f"- {e}")
if r.remediation:
lines.append("**Remediation:**")
for rem in r.remediation:
lines.append(f"- {rem}")
lines.append("")
return "\n".join(lines)
# --- Example Usage ---
if __name__ == "__main__":
config = EntityConfig(
entity_name="Example EU Payment Institution",
threat_intel_sources=[
ThreatIntelSource("ENISA Threat Landscape", ThreatIntelTier.STRATEGIC, 365,
date(2026, 2, 1), feeds_into_framework=True),
ThreatIntelSource("FS-ISAC", ThreatIntelTier.OPERATIONAL, 7,
date(2026, 4, 10), feeds_into_framework=True),
ThreatIntelSource("CVE/NVD Feed", ThreatIntelTier.TECHNICAL, 1,
date(2026, 4, 16), feeds_into_framework=False),
],
post_incident_reviews=[
PostIncidentReview(
incident_id="INC-2026-001",
incident_date=date(2026, 1, 15),
severity=IncidentSeverity.MAJOR,
resolution_date=date(2026, 1, 17),
rca_completed=True,
rca_completion_date=date(2026, 2, 5), # 19 days — compliant
corrective_action_plan=True,
cap_completion_date=date(2026, 2, 28), # 42 days — compliant
lessons_learned_report=True,
ll_sign_off_date=date(2026, 3, 15), # 57 days — compliant
framework_update_triggered=True,
third_party_involved=True,
third_party_cooperation_documented=True,
),
],
framework_revisions=[
FrameworkRevision("v2.0", date(2025, 11, 1), "annual",
management_sign_off=True, next_review_date=date(2026, 11, 1)),
FrameworkRevision("v2.1", date(2026, 2, 20), "incident",
"INC-2026-001", management_sign_off=True),
],
training_records=[
TrainingRecord("Annual Security Awareness", "all_staff",
date(2026, 3, 1), completion_rate_pct=96.0),
TrainingRecord("Board Cybersecurity Briefing", "management_body",
date(2026, 2, 15), completion_rate_pct=100.0,
management_body_included=True),
TrainingRecord("DORA Obligations — Contract Managers", "specialist",
date(2026, 1, 20), completion_rate_pct=88.0),
],
isac_membership=True,
sector_learning_register_maintained=True,
)
checker = DORALearningEvolvingChecker(config)
report = checker.run_full_assessment()
print(report.to_markdown())
print(report.summary())
9. DORA × NIS2 Art.21(2) Dual-Compliance Mapping
Financial entities subject to both DORA (as financial sector entities) and NIS2 (as operators of essential services) benefit from coordinated compliance. DORA is lex specialis for financial entities under NIS2 Art.3(1) — DORA compliance satisfies equivalent NIS2 requirements. The Art.13 learning loop maps directly to NIS2 Art.21(2) measures:
| DORA Art.13 Requirement | NIS2 Art.21(2) Mapping | Dual-Compliance Note |
|---|---|---|
| Art.13(1): Threat intelligence gathering | Art.21(2)(b): Incident handling + threat monitoring | DORA scope broader (all ICT threats, not just incidents) |
| Art.13(2): Post-incident RCA | Art.21(2)(b): Post-incident analysis | DORA requires RCA within defined timelines; NIS2 less prescriptive |
| Art.13(3): Framework update cadence | Art.21(2)(a): Risk analysis and ICT security policies | DORA mandates annual minimum; NIS2 references "appropriate" measures |
| Art.13(4): Security awareness training | Art.21(2)(g): Cybersecurity awareness + basic training | DORA requires management body training explicitly (Art.5(3) linkage) |
| Art.13(5): Sector learning / info sharing | Art.21(2)(h): Vulnerability disclosure + information sharing | DORA Art.45 voluntary sharing + Art.13(5) learning obligation |
| Post-incident review → ICTRMF update | Art.21(1): Risk-proportionate measures, regularly reviewed | DORA "at least annually" > NIS2 "regularly" — DORA sets the higher bar |
| Third-party cooperation in reviews | Art.21(2)(h) + NIS2 Art.21(3): Supply chain | DORA Art.30 contract clause requirement more specific than NIS2 |
Key lex specialis principle: NCA supervision under DORA satisfies equivalent NIS2 supervisory requirements for financial entities. A single audit trail covering Art.13 satisfies both frameworks — no duplication of evidence needed.
10. Common NCA Audit Failures — Art.13
Based on supervisory guidance and peer entity assessments, seven Art.13 failure patterns recur in NCA examinations:
-
RCA without root cause: Post-incident reviews document what happened (timeline) but not why it happened (root cause). "Server went down" is a description; "Unpatched CVE-2025-XXXX in load balancer firmware, missed due to absent patch management process for network devices" is a root cause.
-
CAP without owners: Corrective Action Plans list actions without named owners or measurable deadlines. NCAs require SMART milestones with accountability.
-
Framework version without delta: New framework versions are issued without documenting what changed from the previous version. Version history must include change summaries, not just dates.
-
Training completion without management body: Security awareness training covers all staff but management body participation is treated as optional or is not separately tracked. Art.5(3) makes management body training mandatory.
-
Threat intel without analysis: Financial entities subscribe to threat feeds but cannot demonstrate that feed content was analysed for relevance to their asset inventory. Subscription receipts ≠ analysis evidence.
-
Sector learning without a register: Entities participate in information sharing forums but have no documented register of sector incidents reviewed and actions taken. The obligation is to draw lessons, not merely to receive information.
-
Incident-triggered updates without documentation: The ICTRMF is updated in response to incidents but the update is not formally documented as an "incident-triggered revision" with reference to the triggering RCA. The linkage must be explicit.
11. The 25-Item NCA Audit Checklist (Art.13)
Art.13(1): Threat Intelligence (5 items)
- TI-01 Threat intelligence program covers all three tiers (strategic / operational / technical)
- TI-02 Each source has a defined review frequency with a responsible owner
- TI-03 Stale sources (not reviewed within frequency window) are tracked and escalated
- TI-04 Threat analysis process documented: how threat intel translates to impact assessment
- TI-05 At least one documented instance of threat intel feeding into Art.13(3) framework update
Art.13(2): Post-Incident Reviews (8 items)
- PIR-01 Post-incident review policy defines scope, process, and timeline requirements
- PIR-02 All major ICT incidents (Art.18(1)) have a completed RCA within 30 days
- PIR-03 RCA documentation distinguishes root cause from proximate/contributing factors
- PIR-04 Corrective Action Plan with SMART milestones exists for each major incident
- PIR-05 Lessons Learned Report signed off by management body within 60 days
- PIR-06 Framework update triggered where RCA identifies systemic gaps (Art.13(3) linkage)
- PIR-07 Third-party incidents: cooperation requirement documented in service contracts
- PIR-08 Third-party cooperation evidence collected for incidents involving ICT service providers
Art.13(3): Framework Updates (5 items)
- FU-01 ICTRMF version history maintained (version, date, type, approver, delta summary)
- FU-02 Annual review scheduled as dedicated calendar item with management body sign-off
- FU-03 Incident-triggered revisions reference the triggering RCA explicitly
- FU-04 Supervisory-triggered revisions reference the supervisory finding/instruction
- FU-05 Testing-triggered revisions (post-TLPT) reference the test report and remediation plan
Art.13(4): Security Awareness Training (4 items)
- SAT-01 Annual ICT security awareness program covers all staff with ≥90% completion rate
- SAT-02 Management body participates in dedicated cybersecurity training (individual attestations)
- SAT-03 Role-based training covers ICT operations, incident responders, and contract managers
- SAT-04 Training records retained for minimum 5 years (7 years for incident-triggered training)
Art.13(5): Sector Learning (3 items)
- SL-01 FS-ISAC or equivalent sector ISAC membership active and documented
- SL-02 Sector learning register maintained: each bulletin reviewed + action documented
- SL-03 TLPT outcomes (Art.26/Art.27) integrated into framework update process (Art.13(3) linkage)
12. 12-Week Art.13 Implementation Timeline
| Week | Focus Area | Deliverable |
|---|---|---|
| 1-2 | Threat Intelligence Audit | Inventory all current sources; map to tiers; identify gaps |
| 2-3 | TI Process Design | Document analysis process; assign owners; define escalation criteria |
| 3-4 | PIR Policy | Draft post-incident review policy; define timelines and templates |
| 4-5 | PIR Backlog | Review all prior major incidents; identify missing RCAs/CAPs/LLRs |
| 5-6 | Framework Versioning | Implement version control; produce current version with full delta history |
| 6-7 | Annual Review Process | Schedule annual review; define input sources; create management body agenda |
| 7-8 | Training Gap Assessment | Audit existing programs; identify coverage gaps (management body, roles) |
| 8-9 | Training Program Update | Update content based on recent incidents; add management body session |
| 9-10 | Sector Learning Register | Join FS-ISAC (if not member); implement register template |
| 10-11 | DORALearningEvolvingChecker | Deploy self-assessment tool; run initial assessment |
| 11-12 | Evidence Package | Compile Art.13 NCA evidence folder; run checklist; management sign-off |
What Comes Next in the DORA Series
DORA Chapter II ends with Art.14 (Communication), which governs internal and external communication plans for ICT-related incidents — a distinct requirement from the incident reporting obligations of Art.17-23. The Chapter III series on threat-led penetration testing (Art.24-27) covers the TLPT program that directly feeds back into Art.13(3) via testing-triggered framework updates.