DEV Community

Cover image for DORA Oversight Guide 2025: What JET Will Check
Pentest Testing Corp
Pentest Testing Corp

Posted on

DORA Oversight Guide 2025: What JET Will Check

Financial institutions and SaaS/ICT providers supporting them will be examined under the ESAs’ DORA oversight guide 2025. The guide explains how Joint Examination Teams (JET)—coordinated by a Lead Overseer across EBA/ESMA/EIOPA—will supervise critical third-party ICT providers (CTPPs) and verify resilience in practice. This DEV-oriented post translates the guide into an evidence-first checklist, with copy-paste code to stand up an audit-ready evidence register, automate incident reporting artifacts, and align testing (incl. TLPT-style scenarios).

DORA Oversight Guide 2025: What JET Will Check

If you want a quick outside-in check while you assemble evidence, run our free website vulnerability scanner and attach the screenshots/reports to your evidence pack: free.pentesttesting.com.


What the Oversight Guide Covers (JET focus)

Scope & players (EBA/ESMA/EIOPA)

  • Who is in scope: designated CTPPs and the ICT services they provide to EU financial entities.
  • How oversight works: JETs perform examinations and monitoring under a Lead Overseer model; national competent authorities contribute expertise; governance uses formal forums for prioritization and information-sharing.
  • What gets examined: governance and risk management, incident/major-outage handling, testing and scenario exercises (including TLPT-aligned practices), data portability & exit strategies, third-party/sub-outsourcing chains, and concentration risk.

What “good” looks like for developers & platform teams

  • Traceability: policies ⇄ controls ⇄ telemetry ⇄ tickets ⇄ test results ⇄ evidence artifacts.
  • Repeatable drills: incident playbooks and failover tests with preserved logs, screenshots, and change records.
  • Measurable SLOs: service-level telemetry mapped to recovery objectives (RTO/RPO) and customer/contract commitments.

Free Website Vulnerability Scanner homepage screenshot:

Screenshot of the free tools webpage where you can access security assessment tools.Screenshot of the free tools webpage where you can access security assessment tools.


Evidence Expectations (make it easy for a JET to follow)

Below is an evidence-first view keyed to common Oversight Guide themes. Each bullet includes what to prove and how to generate/store the proof—with automation you can drop into CI/CD or a nightly job.

1) Governance & risk (incl. EIOPA expectations)

Prove: clear ownership, risk assessment cadence, exceptions with deadlines, change control.
Artifacts: policy PDFs, risk register exports, CAB minutes, signed exception forms, IaC policy checks.

# collect_evidence.sh — nightly snapshot of governance artifacts
set -euo pipefail
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
BASE="evidence/$STAMP/governance"
mkdir -p "$BASE"
cp policies/*.pdf "$BASE"/ || true
cp risk-register/*.csv "$BASE"/ || true
cp change-control/minutes/*.pdf "$BASE"/ || true
tar -czf "evidence/$STAMP-governance.tar.gz" -C "evidence/$STAMP" governance
echo "Wrote evidence/$STAMP-governance.tar.gz"
Enter fullscreen mode Exit fullscreen mode

2) Incident & major-outage reporting

Prove: you can classify, notify, and report within DORA timeframes; show how “major” is decided; preserve forensic trail.

// incident_report.schema.json  align fields to DORA reporting expectations
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "DORA Major Incident Report",
  "type": "object",
  "required": ["id","classification","start_time","detection_time","services_impacted",
               "customers_impacted","confidentiality_impact","integrity_impact",
               "availability_impact","data_exfiltration","root_cause","mitigations",
               "notifications","timeline","evidence_bundle"],
  "properties": {
    "id": {"type":"string"},
    "classification": {"enum":["major","significant","minor"]},
    "start_time": {"type":"string","format":"date-time"},
    "detection_time": {"type":"string","format":"date-time"},
    "services_impacted": {"type":"array","items":{"type":"string"}},
    "customers_impacted": {"type":"integer"},
    "confidentiality_impact": {"type":"string"},
    "integrity_impact": {"type":"string"},
    "availability_impact": {"type":"string"},
    "data_exfiltration": {"type":"boolean"},
    "root_cause": {"type":"string"},
    "mitigations": {"type":"array","items":{"type":"string"}},
    "notifications": {"type":"array","items":{"type":"string"}},
    "timeline": {"type":"array","items":{"type":"object"}},
    "evidence_bundle": {"type":"string"}
  }
}
Enter fullscreen mode Exit fullscreen mode
# classify_incident.py — simple rules to flag “major” and build a JSON file that passes the schema
import json, sys, uuid, datetime as dt
from pathlib import Path

RULES = {
  "availability_minutes": 60,      # >= 60 minutes outage across a key service
  "customers_impacted":  1000,     # or >= 1k customers
  "data_exfiltration":   True      # any exfil = major
}

def classify(event):
    major = False
    reasons = []
    if event.get("availability_minutes",0) >= RULES["availability_minutes"]:
        major = True; reasons.append(">=60min availability impact")
    if event.get("customers_impacted",0) >= RULES["customers_impacted"]:
        major = True; reasons.append(">=1000 customers impacted")
    if event.get("data_exfiltration",False) is True:
        major = True; reasons.append("data exfiltration")
    return ("major" if major else "significant"), reasons

sample = {
  "services_impacted": ["payments-api","auth"],
  "availability_minutes": 72,
  "customers_impacted": 1250,
  "data_exfiltration": False
}

classification, reasons = classify(sample)
report = {
  "id": str(uuid.uuid4()),
  "classification": classification,
  "start_time": dt.datetime.utcnow().isoformat()+"Z",
  "detection_time": dt.datetime.utcnow().isoformat()+"Z",
  "services_impacted": sample["services_impacted"],
  "customers_impacted": sample["customers_impacted"],
  "confidentiality_impact": "none",
  "integrity_impact": "low",
  "availability_impact": f"{sample['availability_minutes']} minutes across core APIs",
  "data_exfiltration": sample["data_exfiltration"],
  "root_cause": "upstream DB failover misconfig",
  "mitigations": ["manual failover","connection pool tuning"],
  "notifications": ["internal-SOC","customer-statuspage"],
  "timeline": [{"t": "start", "desc":"API 5xx spike"}, {"t":"mitigation","desc":"manual failover"}],
  "evidence_bundle": "s3://dora-evidence/incidents/2025-10-12-bundle.tar.gz",
  "notes": {"classification_reasons": reasons}
}
Path("out").mkdir(exist_ok=True)
Path("out/incident_report.json").write_text(json.dumps(report, indent=2))
print("Wrote out/incident_report.json")
Enter fullscreen mode Exit fullscreen mode
-- sla_major_incidents.sql — show outages meeting “major” thresholds in last 90 days
WITH incidents AS (
  SELECT id, service, started_at, ended_at,
         EXTRACT(EPOCH FROM (ended_at - started_at))/60 AS minutes,
         customers_impacted, data_exfiltration
  FROM ops_incidents
  WHERE started_at >= NOW() - INTERVAL '90 days'
)
SELECT id, service, minutes, customers_impacted, data_exfiltration,
       CASE WHEN minutes >= 60
                 OR customers_impacted >= 1000
                 OR data_exfiltration = TRUE
            THEN 'major' ELSE 'significant' END AS classification
FROM incidents
ORDER BY started_at DESC;
Enter fullscreen mode Exit fullscreen mode

3) Resilience testing & TLPT alignment

Prove: routine technical tests + scenario-based exercises cover your critical services, with findings tracked to closure.

# dora_testplan.yaml — map critical services to tests and TLPT-like scenarios
services:
  - name: payments-api
    owner: platform
    controls: [waf, rate-limit, mTLS, db-failover]
    tests:
      - type: pentest
        scope: api
        cadence: quarterly
      - type: chaos
        scenario: db_primary_down
        objective: "RTO <= 15m, no data loss"
        evidence: "artifacts/chaos/payments-api-dbdown-*.md"
      - type: tlpt
        scenario: "credential-stuffing -> lateral to ledger"
        objective: "detect & contain within 10m"
        evidence: "tlpt/2025Q3/*"
  - name: auth
    owner: identity
    tests:
      - type: pentest
        scope: oauth, oidc
        cadence: quarterly
Enter fullscreen mode Exit fullscreen mode
# .github/workflows/dora-readiness.yml — nightly “evidence freshness” CI
name: DORA Readiness Nightly
on:
  schedule: [{ cron: "0 1 * * *" }]
jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Validate incident schema
        run: jq -e . out/incident_report.json > /dev/null
      - name: Build evidence register
        run: python3 scripts/build_evidence_register.py
      - name: Publish artifact
        uses: actions/upload-artifact@v4
        with:
          name: dora-evidence-${{ github.run_id }}
          path: evidence/**
Enter fullscreen mode Exit fullscreen mode

4) Data portability & exit strategy (incl. EIOPA priorities)

Prove: you can deliver customer data and configs in a documented, secure format; show an exercised exit runbook.

# export_portability.py — deterministic data+config export (hash + manifest)
import hashlib, json, os, tarfile, time
from pathlib import Path

ROOT="exports/portability"
srcs=["configs/tenant.json","db/snapshots/tenant.dump","infra/terraform.tfstate"]
ts=time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
bundle=f"{ROOT}/export-{ts}.tar.gz"
Path(ROOT).mkdir(parents=True, exist_ok=True)
with tarfile.open(bundle, "w:gz") as tar:
    for p in srcs:
        tar.add(p)

h=hashlib.sha256(Path(bundle).read_bytes()).hexdigest()
manifest={"bundle": bundle, "sha256": h, "created_at": ts, "format": "json+pgdump+tfstate"}
Path(f"{bundle}.manifest.json").write_text(json.dumps(manifest, indent=2))
print("Export:", bundle, "SHA256:", h)
Enter fullscreen mode Exit fullscreen mode

5) Sub-outsourcing & supply-chain transparency

Prove: you know who your providers depend on, where data is processed, and how changes are controlled.

// vendor_sbom.json  software+service BOM for ICT supply chain
{
  "provider": "acme-cloud",
  "services": [
    {"name":"object-storage","region":"eu-west-1","subprocessors":["netops-co","backup-inc"]},
    {"name":"email-relay","region":"eu-central-1","subprocessors":["smtp-pro-1"]}
  ],
  "data_locations": ["DE","IE"],
  "change_control": {"notice_days": 30, "opt_out_supported": true}
}
Enter fullscreen mode Exit fullscreen mode

Readiness Steps You Can Implement This Week

  1. Gap-map your controls to the guide. Create a control-to-oversight map; mark red/yellow/green and owners.
  2. Contract reviews: ensure clauses for incident reporting, testing rights (incl. TLPT), data portability, sub-outsourcing notice, and exit milestones.
  3. Playbook drills: run one failover and one security incident exercise; export timelines, chat logs, and dashboards.
  4. Service-level telemetry: tag SLOs for RTO/RPO and auto-capture dashboards as PDFs into your evidence folder nightly.
  5. Centralize artifacts: stand up a versioned evidence bucket with lifecycle policies.
# terraform — S3 evidence bucket with retention + immutability
resource "aws_s3_bucket" "dora_evidence" { bucket = "acme-dora-evidence" }
resource "aws_s3_bucket_versioning" "ver" {
  bucket = aws_s3_bucket.dora_evidence.id
  versioning_configuration { status = "Enabled" }
}
resource "aws_s3_bucket_lifecycle_configuration" "lc" {
  bucket = aws_s3_bucket.dora_evidence.id
  rule {
    id = "retain-365"
    status = "Enabled"
    noncurrent_version_expiration { noncurrent_days = 365 }
  }
}
Enter fullscreen mode Exit fullscreen mode

For Non-EU Providers: Demonstrate Equivalence & Auditability

To accelerate onboarding under DORA as a non-EU provider:

  • Assurance pack: SOC 2 Type II or ISAE 3000/3402, ISO 27001 certificate & SoA, data-location appendix, and incident reporting playbooks.
  • Control mappings: cross-map your controls to DORA oversight guide 2025 sections—provide a CSV/JSON.
  • Evidence APIs: expose a read-only endpoint for customers to fetch signed artifacts and audit logs.
# evidence_api.py — ultra-simple signed evidence link generator (Flask)
from flask import Flask, jsonify, request
import hmac, hashlib, time, base64

SECRET=b"..."

def sign(path, ttl=3600):
    exp=int(time.time())+ttl
    msg=f"{path}:{exp}".encode()
    sig=base64.urlsafe_b64encode(hmac.new(SECRET, msg, hashlib.sha256).digest()).decode()
    return f"{path}?exp={exp}&sig={sig}"

app=Flask(__name__)

@app.get("/evidence/<path:item>")
def evidence(item):
    return jsonify({"url": sign(f"s3://acme-dora-evidence/{item}")})

app.run(port=8080)
Enter fullscreen mode Exit fullscreen mode
# dora_mapping.csv — sample Controls→Oversight sections
control_id,description,oversight_section,evidence_path
GOV-01,Board-approved risk policy,Governance,evidence/2025-10-12/governance/policies.pdf
INC-03,Incident classification rules,Incident Handling,evidence/2025-10-12/incidents/classifier.md
TEST-07,DB failover exercise Q3,Resilience Testing,evidence/2025-09-20/tests/db-failover/
PORT-02,Export format & hashes,Data Portability,evidence/2025-10-10/exports/manifest.json
Enter fullscreen mode Exit fullscreen mode

Developer Helper: One-shot Evidence Register

# scripts/build_evidence_register.py — create a guide-aligned folder tree
import os, pathlib, json, datetime as dt
ROOT=pathlib.Path("evidence")/dt.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
SECTIONS=["01-governance","02-incident","03-testing-tlpt","04-portability-exit",
          "05-supply-chain","06-telemetry","07-contracts","08-risk-register"]
for s in SECTIONS: (ROOT/s).mkdir(parents=True, exist_ok=True)
index={"root": str(ROOT), "sections": SECTIONS}
(ROOT/"README.json").write_text(json.dumps(index, indent=2))
print("Evidence root:", ROOT)
Enter fullscreen mode Exit fullscreen mode

Sample report (from the free tool) to check Website Vulnerability:

Sample vulnerability assessment report generated with our free tool, providing insights into possible vulnerabilities.Sample vulnerability assessment report generated with our free tool, providing insights into possible vulnerabilities.


Related Services & Internal Links

Recent on our blog:


CTA

Need help to gap-map, test, and package a regulator-ready evidence set?
Email query@pentesttesting.com or start here: Risk Assessment Services and Remediation Services.

Top comments (0)