GDPR Article 33 gives you 72 hours from becoming aware of a personal data breach to notify your supervisory authority. Article 34 requires notifying affected individuals without undue delay where the risk to them is high.

The clock starts at awareness, not at confirmation. A credible report that something leaked starts it; "we were still investigating" does not stop it. This runbook exists so the first hour is not spent deciding who decides.

Roles

Fill these in before you need them. A runbook with blank owners is a document, not a procedure.

RoleWhoResponsibility
Incident lead(fill in)Owns the timeline, calls the decisions
Technical lead(fill in)Scope, containment, evidence
Privacy/legal(fill in)Art. 33/34 assessment, authority contact
Communications(fill in)User and customer messaging

Supervisory authority: SUPERVISORY_AUTHORITY in config/compliance.ts. Notification window: BREACH_NOTIFICATION_HOURS (clamped to 72 — a config typo must not extend a statutory deadline).

Hour 0–1: contain and record

  1. Start a timestamped log. Every action, every decision, who made it. This log is what you hand the authority.
  2. Record the awareness time. This is T0 for the 72 hours. Write it down explicitly rather than inferring it later.
  3. Contain. Revoke exposed credentials, disable the affected path, rotate keys. Containment beats analysis — you can reconstruct scope afterwards.
  4. Preserve evidence. Do not delete logs, do not git push --force, do not clean up the compromised state. Snapshot first.

Key rotation, if credentials are implicated:

bash
# Supabase service key, Stripe secret + webhook secret, JOBS_SECRET_KEY,
# VAPID private key, LOGS_SALT / REFERRAL_SALT / AFFILIATES_SALT.
# Rotating a hashing salt invalidates existing hashes by design — that is
# acceptable for an incident and must be a deliberate call, not a surprise.

Hour 1–24: scope

Determine what data, whose data, and how much. These queries answer the questions the authority will ask.

sql
-- Who accessed what, in the window
select user_id, event_type, ip_address, created_at
from user_access_logs
where created_at between $1 and $2
order by created_at;

-- Admin actions in the window (privilege abuse / compromised admin)
select admin_user_id, action, target_type, target_id, created_at
from admin_logs
where created_at between $1 and $2
order by created_at;

-- Application errors around the incident
select level, category, event, route, status_code, created_at
from error_logs
where created_at between $1 and $2
order by created_at;

-- Affected account count, once you have the id list
select count(distinct id) from accounts where id = any($1);

Record, for the notification:

  • Categories and approximate number of data subjects
  • Categories and approximate number of records
  • Likely consequences
  • Measures taken or proposed

"Approximate" is explicitly allowed. An honest estimate now beats an exact number on day four.

Hour 24–72: notify

Article 33 — supervisory authority

Notify unless the breach is unlikely to result in a risk to the rights and freedoms of natural persons. Document that assessment either way.

If you cannot assemble the full picture in 72 hours, notify anyway and supply the rest in phases — Article 33(4) allows it. A late complete notification is a worse position than an early partial one.

Include: nature of the breach, categories and approximate counts, DPO or contact point, likely consequences, measures taken.

Article 34 — affected individuals

Required where the breach is likely to result in a high risk to individuals. Not required if the data was encrypted or otherwise unintelligible, if you have since neutralised the risk, or if individual contact would be disproportionate (then make a public communication).

Write in plain language. Say what happened, what data, what you did, what they should do, and who to contact. Do not minimise — a notification that reads as damage control invites the complaint you are trying to avoid.

For a breach touching AI features, state plainly whether prompt and conversation content was exposed. Chat history is more revealing than most account data, and burying it under "user records" is the kind of omission that turns an incident into a sanction.

Processor obligations

If you act as a processor for B2B customers, Article 33(2) requires you to notify the controller without undue delay — no 72-hour grace. Your customer DPA likely sets a tighter contractual window. Check it before you rely on the statutory one.

After: close the loop

  • Post-incident review with a written root cause
  • Track remediation to completion, not to ticket-closed
  • Update the DPIA if the risk analysis changed
  • Update this runbook with what actually slowed you down
  • Retain the incident record — you must be able to evidence Art. 33(5) compliance

Register

Article 33(5) requires documenting all breaches, including those you decided not to notify. Keep the register with the reasoning, not just the conclusion.

DateDescriptionData affectedSubjectsNotified?Rationale