--- status: template playbook-section: 20 title: "Security Incident & Personal Data Breach Runbook" gdpr-articles: [Art. 33, Art. 34] last-reviewed: "[FILL IN: YYYY-MM-DD]" --- # Security Incident & Personal Data Breach Runbook > **Template status** — fill every `[FILL IN: …]` marker before use. > Cross-references below point to shipped code and ADRs; do not change them. --- ## 1. Purpose & Scope This runbook governs the detection, triage, containment, notification, and post-mortem of security incidents and personal data breaches affecting `[FILL IN: product / organisation name]`. **In scope:** any event that may have compromised the confidentiality, integrity, or availability of personal data processed by this system, including unauthorized access, exfiltration, accidental exposure, and ransomware. **Out of scope:** non-PII service disruptions (handle via standard on-call runbook). Escalate to this runbook when PII impact cannot be ruled out. --- ## 2. Severity Classification | Level | Definition | Example | | ----------------- | ------------------------------------------------- | ---------------------------------------------------- | | **P0 — Critical** | Confirmed exfiltration or mass exposure of PII | Database dump on public host | | **P1 — High** | Suspected breach; blast radius unknown | Anomalous `EXPORT` audit entries for non-admin actor | | **P2 — Medium** | Contained misconfiguration; no confirmed PII leak | Stale presigned URL exposed to wrong tenant | | **P3 — Low** | Near-miss; no PII accessed | Failed injection attempt blocked by rate-limit | --- ## 3. Roles & Contacts | Role | Name | Contact | | ----------------------- | ------------------------------ | ------------------ | | Incident Commander | [FILL IN: name] | [FILL IN: contact] | | Data Protection Officer | [FILL IN: name / DPO provider] | [FILL IN: contact] | | Legal / Counsel | [FILL IN: name] | [FILL IN: contact] | | Engineering Lead | [FILL IN: name] | [FILL IN: contact] | | Communications Lead | [FILL IN: name] | [FILL IN: contact] | **Supervisory Authority (SA):** - Authority name: `[FILL IN: e.g. ICO / CNIL / BfDI]` - Online notification portal: `[FILL IN: URL]` - Emergency phone: `[FILL IN: number]` --- ## 4. Phase 1 — Detection ### 4.1 Automated signals This template ships two automated detection surfaces. Check both when an alert fires. #### Sentry error alerting (ADR-014) Every unhandled exception in `apps/web-next`, `apps/cms`, and `apps/web-tanstack` is captured via `ILogger.captureException` and routed to Sentry ([`docs/decisions/adr-014-instrumentation-sentry.md`](../../decisions/adr-014-instrumentation-sentry.md)). Configure alert rules in Sentry for: - Spike in `4xx` / `5xx` on auth or DSR routes - New issue fingerprints in production environment - Volume anomaly on `[FILL IN: Sentry project slug]` **Verify DSNs are configured:** ```bash # Each app has its own Sentry project echo $WEB_NEXT_SENTRY_DSN echo $CMS_SENTRY_DSN echo $WEB_TANSTACK_SENTRY_DSN # if TanStack Start app is in use ``` All three must be non-empty in production. A missing DSN silently disables capture for that app. #### Audit log anomalies (ADR-018) The audit channel ([`docs/decisions/adr-018-audit-and-compliance.md`](../../decisions/adr-018-audit-and-compliance.md)) records every `AuditAction` emitted by feature use cases via `AuditLogProtocol.record()`. Actions relevant to breach detection: | `AuditAction` | Breach signal | | ------------------- | ----------------------------------------------------- | | `EXPORT` | Mass export by non-admin actor or from unexpected IP | | `VIEW` | High-frequency reads on a single `actorId` | | `PERMISSION_CHANGE` | Privilege escalation outside change-management window | | `DELETE` | Bulk delete with no corresponding DSR request | Query the Payload audit logs collection or the aggregated cold archive (`[FILL IN: log aggregation URL, e.g. Vector / Fluent Bit sink]`) for anomalies. Correlate with OTel `correlationId` (trace ID auto-populated by `TraceIdEnrichingAuditLog`). #### Rate-limit exhaustion (ADR-025 § Epic C) The rate-limit primitive (`IRateLimit` in `core-shared/rate-limit`, see [`docs/guides/rate-limiting.md`](../../guides/rate-limiting.md)) emits `{ allowed: false, remaining: 0, resetAt }` when a budget is exhausted. Repeated exhaustion on auth or DSR endpoints may indicate credential-stuffing or automated exfiltration. Check budget tables declared in feature manifests (`rateLimit: { window, budget }`) against observed traffic in `[FILL IN: metrics dashboard URL]`. #### Security header violations HSTS, `X-Frame-Options`, and CSP headers are emitted by the security-headers middleware ([`docs/guides/security-headers.md`](../../guides/security-headers.md)). CSP violation reports (if `report-uri` is configured) surface attempted XSS. Check `[FILL IN: CSP report endpoint / dashboard]`. ### 4.2 Manual discovery If detection was by human observation (e.g., responsible-disclosure report, darknet alert): 1. Log the reporter's contact and discovery timestamp. 2. Do not confirm or deny breach details to the reporter until DPO is engaged. 3. Proceed to Phase 2. --- ## 5. Phase 2 — Triage **Target time: within [FILL IN: e.g. 2 hours] of detection.** ### 5.1 Triage checklist - [ ] Page Incident Commander and DPO. - [ ] Open incident channel: `[FILL IN: e.g. #incident-YYYYMMDD in Slack / Teams]`. - [ ] Document initial facts: detected at, detected by, affected system(s). - [ ] Classify severity (§ 2). - [ ] Determine if personal data is involved (see § 5.2). - [ ] Initiate 72-hour DPA notification clock if P0 or P1 (§ 7.1). ### 5.2 PII impact assessment Use the generated data map (`compliance/data-map.yml`, generated by `pnpm compliance:data-map` from Payload `custom.pii` field tags) to enumerate which collections and fields may be affected. Cross-reference with the scope of the incident (endpoint, DB table, S3 bucket, etc.). Key questions: - Which `piiCategory` values are in the affected scope? (e.g. `contact-email`, `identification-name`) - Are any `restrictable: true` subjects affected (i.e. users who invoked Art. 18)? - Was the `auditLogs` collection itself compromised? (Audit trail integrity is required for Art. 33 notification.) --- ## 6. Phase 3 — Containment **Target time: within [FILL IN: e.g. 4 hours] of confirmation for P0/P1.** ### 6.1 Immediate actions - [ ] Revoke or rotate compromised credentials (`[FILL IN: credential management system]`). - [ ] Block actor at network/WAF level if attack is ongoing (`[FILL IN: WAF / CDN control panel URL]`). - [ ] If a specific `actorId` is confirmed malicious: suspend account in Payload admin (`apps/cms`, port 3001). - [ ] If a tRPC or REST route is the attack vector: deploy an emergency rate-limit tightening or disable the route (`[FILL IN: deployment method]`). - [ ] Preserve evidence: take read-only snapshots of affected tables, CloudWatch / log streams, and network flow logs before any cleanup. ### 6.2 Audit trail preservation The audit log collection is append-only (`update: () => false` Payload access rule per ADR-018). Do not attempt to delete or modify audit entries. If the audit collection itself is a target, freeze DB-level access and take a snapshot: ```bash # [FILL IN: adapt to your database provider] pg_dump --schema-only --table=audit_logs $DATABASE_URL > audit_logs_schema_snapshot.sql pg_dump --data-only --table=audit_logs $DATABASE_URL > audit_logs_data_snapshot.sql ``` --- ## 7. Phase 4 — Notification ### 7.1 Regulatory notification deadlines | Obligation | Deadline | Trigger | | -------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------- | | GDPR Art. 33 — notify Supervisory Authority | **72 hours** from becoming aware | Any breach involving personal data unless unlikely to risk rights/freedoms | | `[FILL IN: national DPA requirement]` | **[FILL IN: e.g. 24 hours]** | `[FILL IN: condition]` | | GDPR Art. 34 — notify affected data subjects | Without undue delay | High risk to rights and freedoms | **Clock start:** the moment the organisation "becomes aware" — typically when the Incident Commander or DPO confirms the incident in § 5.1, not when it was first detected. ### 7.2 Supervisory Authority notification (Art. 33) Prepare the notification using the SA's online portal (`[FILL IN: URL]`). Required fields per Art. 33(3): - Nature of the breach (categories and approximate number of records / data subjects) - Name and contact details of DPO: `[FILL IN: DPO name, email, phone]` - Likely consequences of the breach - Measures taken or proposed Attach: - Incident timeline (from detection to containment) - Affected `piiCategories` from `compliance/data-map.yml` - Audit log extract covering the incident window (redact unrelated subjects) **If full facts are not available within 72 hours:** submit an initial notification marked "partial" and follow up without delay. GDPR Art. 33(4) explicitly permits phased notification. ### 7.3 Data subject notification (Art. 34) Threshold: notification is required when the breach is likely to result in **high risk** to the rights and freedoms of individuals (e.g. identity theft, financial loss, discrimination). - Drafting: `[FILL IN: communications lead]` drafts notice in plain language. - Channel: `[FILL IN: e.g. in-app banner + email via transactional provider]` - Content: nature of breach, DPO contact, likely consequences, mitigation steps. - Timing: `[FILL IN: target send window, e.g. within 48 hours of Art. 33 notification]` ### 7.4 Internal stakeholder notification | Stakeholder | When | Channel | | ----------------------- | ---------------------------- | ----------- | | Executive team | P0/P1: immediately | `[FILL IN]` | | Customer success | Before customer-facing comms | `[FILL IN]` | | Board / audit committee | Within `[FILL IN]` hours | `[FILL IN]` | --- ## 8. Phase 5 — Post-mortem **Target: within [FILL IN: e.g. 5 business days] of containment.** ### 8.1 Post-mortem checklist - [ ] Timeline reconstruction (detection → triage → containment → notification). - [ ] Root cause analysis (five-whys or equivalent). - [ ] Blast radius: confirmed data subjects affected, `piiCategories` exposed, duration of exposure. - [ ] Audit log review: were anomalous `AuditAction` entries present before detection? Were `from.ipTruncated` values suspicious? - [ ] Control gaps identified. - [ ] Remediation actions with owner and deadline. - [ ] Lessons learned. ### 8.2 Remediation tracking Document each action in `[FILL IN: issue tracker, e.g. Linear / GitHub Issues]` with: - Linked ADR or guide (e.g. ADR-018, ADR-014) - Owner - Target date - Verification step (e.g. `pnpm fallow:audit` green, new test added) ### 8.3 Mandatory follow-up with Supervisory Authority If the Art. 33 notification was submitted as "partial", file the complete notification with the SA by `[FILL IN: agreed follow-up date]`. --- ## 9. Appendix — Command Reference ```bash # Inspect running apps and their Sentry DSN status echo $WEB_NEXT_SENTRY_DSN && echo $CMS_SENTRY_DSN # Run fallow audit to surface dead exports / drift before post-mortem PR pnpm fallow:audit # Regenerate data map to confirm affected PII fields pnpm compliance:data-map # Re-emit all compliance artifacts (data-map + retention-policy + sub-processors) pnpm compliance:emit-all ``` --- ## 10. Document Control | Field | Value | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Owner | [FILL IN: DPO or Engineering Lead] | | Review cycle | [FILL IN: e.g. annual or after every P0/P1] | | Next review date | [FILL IN: YYYY-MM-DD] | | Cross-references | [`docs/decisions/adr-018-audit-and-compliance.md`](../../decisions/adr-018-audit-and-compliance.md), [`docs/decisions/adr-014-instrumentation-sentry.md`](../../decisions/adr-014-instrumentation-sentry.md), [`docs/decisions/adr-025-eu-compliance-baseline.md`](../../decisions/adr-025-eu-compliance-baseline.md), [`docs/guides/audit-and-compliance.md`](../../guides/audit-and-compliance.md), [`docs/guides/rate-limiting.md`](../../guides/rate-limiting.md), [`docs/guides/security-headers.md`](../../guides/security-headers.md) |