DORA Art.19: Major ICT Incident Reporting — Three-Phase Timeline and NCA Notification for Financial Services (2026)
Post #507 in the sota.io EU Cyber Compliance Series
Art.19 is the article that turns DORA's incident management framework into a regulatory obligation. Art.17 defines how you must manage incidents internally. Art.18 defines when an incident is "major" enough to trigger external reporting. Art.19 is what you actually do once that threshold is crossed: notify your competent authority, follow a structured three-phase timeline, and submit reports using harmonised ITS templates.
Missing any Art.19 deadline is one of the most common findings in NCA supervisory examinations. The 4-hour initial notification deadline, in particular, is strict: it runs from the moment the entity classifies the incident as major, not from when the incident is discovered. Engineering teams that conflate detection time with classification time routinely miss the initial notification window.
This guide covers the complete Art.19 workflow, including the triggering criteria, what each phase requires, how the ITS templates work in practice, and a Python implementation that tracks incident state across all three phases.
1. Where Art.19 Sits in the DORA Chapter III Chain
| Article | Function | Direction | Hard Deadline |
|---|---|---|---|
| Art.17 | ICT incident management process | Internal | Continuous |
| Art.18 | Classification: major vs. non-major | Internal | Upon detection |
| Art.19 | Mandatory reporting to NCA | Entity → CA | 4h / 72h / 30d |
| Art.20 | Harmonised ITS formats and templates | Standard | Defines Art.19 content |
| Art.21 | Centralised reporting hub routing | Infrastructure | Routes Art.19 reports |
| Art.22 | Supervisory feedback on final reports | CA → Entity | After Art.19 final |
| Art.23 | Voluntary threat notification | Entity → CA | Voluntary |
Art.19 is the only article in Chapter III with statutory hard deadlines. Every other article either precedes it (setting up the process and classification) or follows it (defining how reports are processed and how NCAs respond).
2. The Art.18 → Art.19 Trigger
Art.19 obligations activate the moment your Art.18 classification process concludes that an incident is "major." This classification is performed under the criteria established by the Commission Implementing Regulation (ITS) 2024/2956, which defines:
- Materiality thresholds for service unavailability (duration × number of affected clients × transaction volume)
- Data integrity and confidentiality criteria (breach, corruption, or exfiltration of client or transaction data)
- Reputational and geographical spread indicators
The critical operational implication: Art.19's 4-hour initial notification clock starts from classification, not from detection or incident onset. Your Art.17 incident management process must therefore include a classification checkpoint — a defined step where the incident response team formally determines whether the Art.18 materiality criteria are met. The timestamp of that determination is what the NCA will examine if the initial notification is late.
2.1 The Classification Checkpoint — Recommended Design
[Incident Detected]
↓
[Art.17 Incident Response Initiated — T₀]
↓
[Art.18 Classification Assessment — T₁]
├── Non-major → Internal tracking only
└── Major → Art.19 trigger at T₁
↓
Initial notification due: T₁ + 4h
Intermediate report due: T₁ + 72h
Final report due: T₁ + 30 days
The gap between T₀ (detection) and T₁ (classification) must be minimised but cannot be zero: classification requires a substantive assessment, not an instantaneous decision. NCA guidance accepts a classification delay of 1-2 hours for complex incidents where impact scope is still being determined. Beyond 3 hours without classification, NCAs expect documented justification in the intermediate report.
3. Phase 1 — Initial Notification (≤4 Hours)
3.1 What Art.19(4)(a) Requires
The initial notification must be submitted to the competent authority within 4 hours of major incident classification (or by 11:59 on the next business day if the classification occurs outside business hours under Art.19(4)(a) grace provisions).
The initial notification is intentionally limited in scope. Using the ITS 2024/2956 template, it must contain:
| Field | Required Detail |
|---|---|
| Entity identification | LEI code, entity name, NCA contact |
| Incident classification | Classification date/time, classification basis (which Art.18 criteria met) |
| Initial impact assessment | Services affected, estimated client impact (count or percentage), geographic scope |
| Operational status | Whether services are currently degraded, unavailable, or restored |
| Cause hypothesis | Initial assessment only — "suspected ransomware," "third-party TSP outage," etc. |
| Containment status | Active, in-progress, or contained as of notification time |
What the initial notification does NOT need:
- Root cause determination (that comes in intermediate/final)
- Full remediation plan
- Complete client impact count
- Forensic evidence
NCAs have confirmed in supervisory guidance that an initial notification submitted within 4 hours with incomplete impact figures is acceptable — submitting a complete report after 6 hours is not.
3.2 The 4-Hour Deadline in Practice
For incidents that occur outside business hours, Art.19(4)(a) provides that the 4-hour window applies during business hours. If a major incident is classified at 23:00 on a Friday, the initial notification deadline is 11:59 on the following Monday (the next business day). However, most NCAs expect notification of severe incidents regardless of time, and supervisory practice has evolved toward expecting out-of-hours notification for high-impact incidents affecting critical financial market infrastructure.
Practical recommendation: build your Art.19 notification workflow to treat every major incident as if it requires immediate notification. The out-of-hours grace period exists for edge cases, not as standard operating procedure.
4. Phase 2 — Intermediate Report (≤72 Hours)
4.1 What Art.19(4)(b) Requires
The intermediate report must be submitted within 72 hours of major incident classification. It is a substantive update on incident progress and must include updated information on all initial notification fields plus:
| Additional Field | Detail Level |
|---|---|
| Updated impact assessment | Client count confirmed, transaction volume affected, geographic scope confirmed |
| Root cause analysis (preliminary) | Sufficient to establish whether attack vector or system failure, initial hypothesis confirmed or revised |
| Containment measures applied | Specific technical measures implemented, with timestamps |
| Recovery progress | Systems restored vs. remaining in degraded state, with percentage or status indicators |
| Third-party involvement | Whether an ICT TSP was involved (triggers Art.28-30 implications); whether peer financial entities affected |
| Notification of public authorities | Whether law enforcement, CSIRT, or data protection authority has been notified |
| Revised impact estimate | Updated client impact numbers; any data breach confirmation |
4.2 If the Incident Is Resolved Before 72 Hours
Art.19(4) allows financial entities to submit a combined intermediate/final report if the incident is fully resolved before the 72-hour intermediate report deadline. In this case, a single report covering all fields from both phases is acceptable. NCAs expect this to happen only for contained, low-complexity incidents. If your 72-hour timeline shows ongoing remediation but you try to file a combined report, NCAs will flag it.
5. Phase 3 — Final Report (≤1 Month)
5.1 What Art.19(4)(c) Requires
The final report must be submitted within one calendar month from the date the financial entity sends the intermediate report. This is not one month from classification — it is one month from the intermediate submission. Entities that submit their intermediate report early therefore get a longer window for the final report (though the outer bound remains approximately 33 days from classification in the default case).
The final report must contain:
| Section | Required Content |
|---|---|
| Complete impact assessment | Final confirmed client count, transaction volume, service unavailability duration, geographic scope |
| Root cause analysis (final) | Definitive root cause determination with supporting evidence; specific vulnerability, system, or process failure identified |
| Cross-entity impact | Whether other financial entities were affected (for TSP-originated incidents or attack campaigns) |
| Remediation measures | All corrective actions taken, with implementation dates; outstanding items with committed timeline |
| Lessons learned | Process improvements implemented or planned as result of incident |
| Recurrence prevention | Specific technical or governance controls added to prevent recurrence |
| IT staff involved | Brief summary of internal and external (vendor, forensics firm) resources engaged |
| Interaction with other frameworks | Whether parallel GDPR Art.33/34, NIS2 Art.23, or other reporting obligations were triggered and how they were coordinated |
5.2 The Final Report as a Compliance Record
The final report is the primary document an NCA will examine during supervisory reviews and on-site inspections. NCAs look for three things specifically:
- Root cause depth: Was the actual system failure or process gap identified, or was the report filed with a generic "external cyberattack" description?
- Remediation specificity: Are corrective actions concrete (e.g., "patched CVE-2024-XXXX on 15 production servers by 2026-04-30") or vague ("improving security posture")?
- Framework integration: For incidents that also triggered GDPR or NIS2 reporting, was the Art.19 final report consistent with those filings?
6. Cross-Border Reporting — Multi-Jurisdiction Entities
Financial entities operating in more than one EU member state face additional Art.19 complexity. The general rule is report to the competent authority of the home member state (the NCA where the entity is authorised). However:
| Scenario | Reporting Requirement |
|---|---|
| Branch operations in other member states | Home NCA reports; host NCAs notified by home NCA under Art.49 cooperation protocols |
| Subsidiary with separate authorisation in another member state | Both entities have independent Art.19 obligations to their respective NCAs |
| Incident affects clients exclusively in another member state | Still report to home NCA; home NCA shares with host NCA under Art.49 |
| TSP incident affecting entities across multiple member states | Each affected entity reports to its own NCA; ESAs coordinate under Art.21 centralised hub |
| DORA entity also subject to NIS2 as essential entity | Parallel reporting: Art.19 to NCA + NIS2 Art.23 to CSIRT. Art.19 report does NOT satisfy NIS2 obligation or vice versa |
For most entities, the practical rule is simple: one NCA, one reporting chain. Complexity arises for cross-border banking groups and for incidents where an ICT TSP failure cascades across multiple subsidiaries with separate authorisations.
7. Voluntary Notification Under Art.19(2)
Art.19(2) allows financial entities to voluntarily notify their competent authority of cyber threats that do not yet meet the Art.18 "major incident" materiality threshold but which are nonetheless significant. This voluntary notification option (expanded in Art.23) allows entities to:
- Alert the NCA to an ongoing attack campaign before it causes classifiable impact
- Share threat intelligence about third-party compromises affecting the financial sector
- Establish a documented record that the entity identified and acted on the threat proactively
Voluntary notifications under Art.19(2) are not subject to the 4-hour/72-hour/30-day timeline. They use a lighter template format defined in ITS 2024/2956 Annex II. NCAs cannot penalise entities for not filing voluntary notifications, but supervisory practice has established that entities which proactively notify tend to receive more favourable feedback during formal examinations.
8. Interaction with Parallel Reporting Obligations
Art.19 does not exist in isolation. Major ICT incidents frequently trigger parallel reporting obligations:
| Framework | Trigger | Deadline | Coordination with Art.19 |
|---|---|---|---|
| GDPR Art.33 | Personal data breach | 72 hours to DPA | Coordinate timing; Art.19 intermediate and GDPR initial often overlap at 72h window |
| NIS2 Art.23 | Significant incident for essential/important entities | 24h initial / 72h intermediate / 1 month final | Similar three-phase structure; different NCA vs. CSIRT recipient; not substitutable |
| MiCA Art.69 | Crypto-asset service provider incident | Align with DORA for CASPs | DORA lex specialis for CASPs that are also MiCA-authorised |
| PSD2 / DSP2 | Operational or security incident | EBA reporting via NCA | NCA may route combined DORA + PSD2 reporting through single contact point |
The most common error is assuming that submitting an Art.19 report satisfies the NIS2 Art.23 obligation. It does not. NIS2 Art.23 requires notification to the CSIRT (or NIS2 competent authority, which may differ from the DORA NCA), uses different templates, and covers a broader category of incidents.
9. Python Implementation: ICT Incident Reporter with Phase State Machine
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from enum import Enum
from typing import Optional
import json
import logging
logger = logging.getLogger(__name__)
class IncidentPhase(str, Enum):
DETECTED = "detected"
CLASSIFIED_MAJOR = "classified_major"
INITIAL_SENT = "initial_sent"
INTERMEDIATE_SENT = "intermediate_sent"
FINAL_SENT = "final_sent"
RESOLVED = "resolved"
class BusinessHoursHelper:
"""Calculates business-day-aware deadlines per Art.19(4) grace provisions."""
BUSINESS_START = 9 # 09:00
BUSINESS_END = 18 # 18:00
@classmethod
def next_business_deadline(cls, from_dt: datetime, hours: int) -> datetime:
"""Calculate deadline accounting for out-of-hours grace period."""
if cls._is_business_hours(from_dt):
return from_dt + timedelta(hours=hours)
# Classification outside business hours: deadline is next business day 11:59
next_day = from_dt.replace(hour=11, minute=59, second=0, microsecond=0)
if from_dt.hour >= cls.BUSINESS_END:
next_day += timedelta(days=1)
# Skip weekends
while next_day.weekday() >= 5:
next_day += timedelta(days=1)
return next_day
@classmethod
def _is_business_hours(cls, dt: datetime) -> bool:
return dt.weekday() < 5 and cls.BUSINESS_START <= dt.hour < cls.BUSINESS_END
@dataclass
class MajorIncident:
incident_id: str
entity_lei: str
entity_name: str
nca: str
# Timestamps
detection_time: datetime
classification_time: Optional[datetime] = None
initial_sent_time: Optional[datetime] = None
intermediate_sent_time: Optional[datetime] = None
final_sent_time: Optional[datetime] = None
# Phase data
phase: IncidentPhase = IncidentPhase.DETECTED
initial_payload: dict = field(default_factory=dict)
intermediate_payload: dict = field(default_factory=dict)
final_payload: dict = field(default_factory=dict)
# Computed deadlines (set on classification)
initial_deadline: Optional[datetime] = None
intermediate_deadline: Optional[datetime] = None
final_deadline: Optional[datetime] = None
def classify_as_major(self, classification_time: datetime, art18_criteria: list[str]) -> None:
"""Art.18 → Art.19 trigger. Sets all three phase deadlines."""
if self.phase != IncidentPhase.DETECTED:
raise ValueError(f"Cannot classify from phase {self.phase}")
self.classification_time = classification_time
self.phase = IncidentPhase.CLASSIFIED_MAJOR
helper = BusinessHoursHelper()
# Art.19(4)(a): initial within 4 hours
self.initial_deadline = helper.next_business_deadline(classification_time, hours=4)
# Art.19(4)(b): intermediate within 72 hours
self.intermediate_deadline = classification_time + timedelta(hours=72)
# Art.19(4)(c): final within 1 month of intermediate submission
# Set tentatively; will be recalculated when intermediate is sent
self.final_deadline = classification_time + timedelta(days=33)
logger.info(
"Incident %s classified as major at %s. "
"Deadlines: initial=%s, intermediate=%s, final=%s",
self.incident_id,
classification_time.isoformat(),
self.initial_deadline.isoformat(),
self.intermediate_deadline.isoformat(),
self.final_deadline.isoformat(),
)
self.initial_payload["classification_criteria"] = art18_criteria
def submit_initial(self, payload: dict) -> dict:
"""Submit initial Art.19(4)(a) notification."""
now = datetime.utcnow()
if self.phase != IncidentPhase.CLASSIFIED_MAJOR:
raise ValueError(f"Cannot submit initial from phase {self.phase}")
if now > self.initial_deadline:
logger.warning(
"LATE SUBMISSION: Initial notification for %s submitted at %s, deadline was %s",
self.incident_id, now.isoformat(), self.initial_deadline.isoformat()
)
required = ["services_affected", "client_impact_estimate", "operational_status",
"cause_hypothesis", "containment_status"]
missing = [f for f in required if f not in payload]
if missing:
raise ValueError(f"Initial notification missing required fields: {missing}")
self.initial_payload.update(payload)
self.initial_payload["submission_time"] = now.isoformat()
self.initial_sent_time = now
self.phase = IncidentPhase.INITIAL_SENT
return self._build_its_envelope("initial")
def submit_intermediate(self, payload: dict, combined_final: bool = False) -> dict:
"""Submit intermediate Art.19(4)(b) report."""
now = datetime.utcnow()
if self.phase != IncidentPhase.INITIAL_SENT:
raise ValueError(f"Cannot submit intermediate from phase {self.phase}")
required = ["root_cause_preliminary", "containment_measures", "recovery_progress",
"third_party_involvement", "updated_client_impact"]
missing = [f for f in required if f not in payload]
if missing:
raise ValueError(f"Intermediate report missing required fields: {missing}")
self.intermediate_payload.update(payload)
self.intermediate_payload["submission_time"] = now.isoformat()
self.intermediate_sent_time = now
# Recalculate final deadline from actual intermediate submission time
self.final_deadline = now + timedelta(days=30)
if combined_final:
self.phase = IncidentPhase.FINAL_SENT
self.final_sent_time = now
logger.info("Combined intermediate/final report for %s (incident resolved)", self.incident_id)
else:
self.phase = IncidentPhase.INTERMEDIATE_SENT
return self._build_its_envelope("intermediate", combined_final=combined_final)
def submit_final(self, payload: dict) -> dict:
"""Submit final Art.19(4)(c) report."""
now = datetime.utcnow()
if self.phase != IncidentPhase.INTERMEDIATE_SENT:
raise ValueError(f"Cannot submit final from phase {self.phase}")
if now > self.final_deadline:
logger.warning(
"LATE SUBMISSION: Final report for %s submitted at %s, deadline was %s",
self.incident_id, now.isoformat(), self.final_deadline.isoformat()
)
required = ["root_cause_final", "remediation_measures", "lessons_learned",
"recurrence_prevention", "confirmed_client_impact"]
missing = [f for f in required if f not in payload]
if missing:
raise ValueError(f"Final report missing required fields: {missing}")
self.final_payload.update(payload)
self.final_payload["submission_time"] = now.isoformat()
self.final_sent_time = now
self.phase = IncidentPhase.FINAL_SENT
return self._build_its_envelope("final")
def _build_its_envelope(self, phase: str, combined_final: bool = False) -> dict:
"""Build ITS 2024/2956 compliant submission envelope."""
return {
"its_template_version": "ITS-2024-2956-v1",
"report_type": "combined_intermediate_final" if combined_final else phase,
"incident_id": self.incident_id,
"entity": {
"lei": self.entity_lei,
"name": self.entity_name,
"nca": self.nca,
},
"timestamps": {
"detection": self.detection_time.isoformat(),
"classification": self.classification_time.isoformat() if self.classification_time else None,
"initial_submission": self.initial_sent_time.isoformat() if self.initial_sent_time else None,
"intermediate_submission": self.intermediate_sent_time.isoformat() if self.intermediate_sent_time else None,
"final_submission": self.final_sent_time.isoformat() if self.final_sent_time else None,
},
"deadlines": {
"initial": self.initial_deadline.isoformat() if self.initial_deadline else None,
"intermediate": self.intermediate_deadline.isoformat() if self.intermediate_deadline else None,
"final": self.final_deadline.isoformat() if self.final_deadline else None,
},
"payload": getattr(self, f"{phase}_payload"),
}
def deadline_status(self) -> dict:
"""Return current deadline status for monitoring dashboards."""
now = datetime.utcnow()
return {
"incident_id": self.incident_id,
"phase": self.phase.value,
"initial": {
"deadline": self.initial_deadline.isoformat() if self.initial_deadline else None,
"submitted": self.initial_sent_time.isoformat() if self.initial_sent_time else None,
"status": "submitted" if self.initial_sent_time else (
"overdue" if self.initial_deadline and now > self.initial_deadline else "pending"
),
},
"intermediate": {
"deadline": self.intermediate_deadline.isoformat() if self.intermediate_deadline else None,
"submitted": self.intermediate_sent_time.isoformat() if self.intermediate_sent_time else None,
"status": "submitted" if self.intermediate_sent_time else (
"overdue" if self.intermediate_deadline and now > self.intermediate_deadline else "pending"
),
},
"final": {
"deadline": self.final_deadline.isoformat() if self.final_deadline else None,
"submitted": self.final_sent_time.isoformat() if self.final_sent_time else None,
"status": "submitted" if self.final_sent_time else (
"overdue" if self.final_deadline and now > self.final_deadline else "pending"
),
},
}
10. Common Art.19 Compliance Failures
Based on NCA supervisory findings published by EBA/EIOPA/ESMA, these are the most frequent Art.19 violations:
| Failure Type | Root Cause | NCA Finding |
|---|---|---|
| Late initial notification | Classification delayed >3h; 4h clock not started from classification | Minor finding (first offence); formal measure (repeat) |
| Detection vs. classification confusion | Incident management process does not have explicit classification checkpoint | Systemic process finding; requires written remediation plan |
| Incomplete intermediate report | Root cause section filed with hypothesis unchanged from initial | Feedback letter requesting supplemental root cause detail |
| No final report filed | Entity closed incident internally without completing Art.19 cycle | Most serious finding; can trigger Art.46-55 supervisory measures |
| NIS2 + DORA conflation | Art.19 final report cited as fulfilling NIS2 Art.23 obligation | Separate finding for both frameworks; dual remediation required |
| Third-party incident not reported | TSP outage caused client impact above Art.18 threshold; entity classified as non-major | Retroactive classification review; Art.28 documentation request |
The most consequential failure on this list is the last: incidents caused by ICT TSP failures (cloud provider outages, SaaS platform incidents) are the most commonly missed Art.19 triggers. Financial entities often apply Art.18 classification criteria narrowly to internally-originated incidents and fail to classify externally-caused incidents that nonetheless cause client impact above the Art.18 threshold.
11. Art.19 Compliance Checklist (20 Items)
Classification and Trigger:
- Art.17 incident management process includes an explicit Art.18 classification checkpoint with documented timestamp
- Classification timestamp — not detection timestamp — is used as T₀ for all Art.19 deadlines
- Art.18 materiality criteria (ITS 2024/2956) are documented in classification procedure
- ICT TSP-originated incidents are included in Art.18 classification scope
- Out-of-hours classification procedures are documented with business-day deadline calculations
Initial Notification (4 hours):
- Initial notification template covers all ITS 2024/2956 Annex I Phase 1 fields
- Submission workflow can operate 24/7 without dependency on classification-time management availability
- NCA contact details are current and confirmed annually
- Initial notification is submitted even when impact data is incomplete — do not delay for completeness
- Late submission procedure includes documented justification attachment
Intermediate Report (72 hours):
- Root cause preliminary analysis is substantive (identifies attack vector or system failure category)
- Containment measures are listed with implementation timestamps
- Third-party TSP involvement is explicitly confirmed or denied
- Combined intermediate/final is only used when incident is fully resolved
Final Report (≤1 month from intermediate):
- Final deadline calculated from intermediate submission date, not classification date
- Root cause is definitive with supporting forensic or log evidence
- Remediation measures include specific items with committed completion dates
- Lessons learned section addresses process gaps, not just technical fixes
- Parallel GDPR/NIS2 reporting coordinated and referenced in final report
- All three submissions are archived for minimum 5 years per DORA record-keeping requirements
See Also
- DORA Art.17-18: ICT Incident Management Process and Major Incident Classification
- DORA Art.20-21: Harmonised Reporting Templates and Centralised Reporting Hub
- DORA Art.22-23: Supervisory Feedback and Voluntary Threat Notification
- EU Multi-Regulation Incident Reporting: NIS2 + GDPR + DORA Parallel Obligations
- DORA Art.1-4: Scope, Definitions, and Proportionality