# BIPA Biometric Data Destruction Runbook **Spec:** docs/PHASE_1_6_BIPA_GATES.md §1 Gate 5 (BIPA §15(a)) **Audience:** Operators (J + named operators with legal-tier credentials) **Status:** Engineering scaffold — ⚖ COUNSEL must review for legal sufficiency before adoption > This runbook tells an operator HOW to destroy biometric data when > a destruction trigger fires. It is a procedural document, not a > design document. The cryptographic substrate that the destruction > writes against (per-subject HMAC audit log + tombstone manifests) > already ships in `crates/catalogd/`. --- ## 1. When this runbook fires Destruction is mandatory when ANY of the following occurs: | Trigger | Source signal | SLA | |---|---|---| | **Retention expiry** | Daily `retention_sweep` flags `consent.biometric.retention_until < now` | 30 days from sweep flagging | | **Consent withdrawal** | Candidate submits withdrawal per consent template §2 | 30 days from receipt | | **Right-to-be-forgotten request** | Candidate submits RTBF request through documented contact channel | 30 days from receipt | | **Court-ordered erasure** | Legal counsel directs erasure via a documented order | Per court order; default 30 days | ⚖ COUNSEL — confirm 30 days is correct for all four. Some deployments have stricter contractual or jurisdictional clocks (CCPA: 45 days but sooner is better; GDPR Art. 17: "without undue delay"). --- ## 2. Pre-destruction checks (5 minutes) Before initiating destruction, the operator MUST: 1. **Verify the trigger.** Cross-reference one of the four sources above. If the trigger is a candidate-initiated request, confirm identity per the standard PII verification procedure (knowledge factor + possession factor; see counsel for the threshold). 2. **Pull the current subject record.** Hit `GET /audit/subject/{candidate_id}` with the legal-tier token. The response includes: - The current `SubjectManifest` (including `consent.biometric.status`) - The full HMAC-chained audit log - `chain_verified: true` (if false, STOP — chain integrity issue must be investigated before destruction) 3. **Check for legal hold.** ⚖ COUNSEL — if a legal hold can apply to a subject's data (litigation, regulatory inquiry, subpoena), document the procedure for checking that no hold is in force before erasing. 4. **Get the second-operator sign-off.** Per BIPA defensibility, destruction is a two-operator action (operator-of-record + one witness). The witness records their attestation in the destruction-event audit row (§4 below). --- ## 3. Destruction procedure ### Step 1 — Erase via identityd Invoke the legal-tier erasure endpoint: ```bash curl -sf -X POST "http://localhost:3100/v1/identity/subjects/${CANDIDATE_ID}/erase" \ -H "Authorization: Bearer $(cat /etc/lakehouse/legal_audit.token)" \ -H "Content-Type: application/json" \ -d '{ "trigger": "retention_expiry|consent_withdrawal|rtbf|court_order", "trigger_evidence_path": "", "operator_of_record": "", "witness": "" }' ``` ⚖ ENGINEERING — `POST /v1/identity/subjects/{id}/erase` is Phase 1.6 Gate 3 dependent. Until it ships, the manual procedure is: a. Set `SubjectManifest.consent.biometric.status = "withdrawn"` and `SubjectManifest.status = "erased"` via direct registry write (operator-of-record only). b. Securely overwrite + unlink the quarantined photo path: `shred -uvz data/biometric/uploads/${CANDIDATE_ID}/*.jpg` (or equivalent for the configured backend). c. NULL the deepface classification fields on the subject row. d. Append the destruction-event audit row (Step 2 below). ### Step 2 — Append the destruction-event audit row The erasure endpoint AUTOMATICALLY writes one row to the subject's per-subject audit log: ```json { "schema": "subject_audit.v1", "ts": "", "candidate_id": "", "accessor": { "kind": "biometric_erasure", "daemon": "identityd", "purpose": "biometric_erasure", "trace_id": "" }, "fields_accessed": ["biometric_classifications", "biometric_data_path", "biometric_template_hash"], "result": "erased", "prev_chain_hash": "", "row_hmac": "" } ``` The HMAC chain extends through the erasure event, so the audit log itself is preserved as anonymous-event proof of compliant destruction even after the underlying biometric data is gone. ### Step 3 — Verify destruction Run the verification script: ```bash ./scripts/staffing/verify_biometric_erasure.sh "${CANDIDATE_ID}" ``` ⚖ ENGINEERING — script TODO. Acceptance: - Subject row biometric fields are NULL - `data/biometric/uploads/${CANDIDATE_ID}/` directory is empty - Most recent audit log row has `result: "erased"`, `accessor.kind: "biometric_erasure"` - Chain still verifies (`chain_verified: true`) under the legal-tier endpoint If any check fails: STOP, do not mark the destruction complete, escalate to engineering. ### Step 4 — Notify the candidate (when applicable) For consent-withdrawal and RTBF triggers, the operator notifies the candidate that destruction is complete. ⚖ COUNSEL — supply the notification template (typically email; medium and language are counsel-determined). --- ## 4. Backup window disclosure Per `IDENTITY_SERVICE_DESIGN.md` v3-B12, biometric data may persist in encrypted system backups for up to **30 days** after destruction (rolling backup window). The candidate must be informed of this when destruction is requested, and the destruction-event audit row records the backup-window expiry date so the operator knows when the residual is fully eliminated. ⚖ COUNSEL — confirm whether the 30-day backup window is acceptable under BIPA. Some interpretations require backups to be addressed within a shorter window; some accept the operational reality of backup retention. --- ## 5. Reporting cadence Monthly, the operator-of-record produces a destruction-events report: ```bash ./scripts/staffing/biometric_destruction_report.sh \ --month "$(date +%Y-%m)" \ --output reports/biometric/destruction_$(date +%Y_%m).md ``` ⚖ ENGINEERING — script TODO. The report aggregates: - Total destruction events in the month - Breakdown by trigger (retention / withdrawal / RTBF / court) - Median time-to-destruction from trigger to completion - Any failures / escalations The monthly report is available to outside counsel on request. It does NOT include candidate-identifying details — only the counts, timings, and cryptographic attestations of the events. --- ## 6. Audit trail attestation The per-subject HMAC chain is the cryptographic substrate that makes destructions defensible after the fact. To produce an attestation for a specific candidate's destruction: 1. Hit `GET /audit/subject/{candidate_id}` with legal-tier token 2. Confirm `chain_verified: true` and most-recent row has `accessor.kind: "biometric_erasure"` 3. Cross-runtime verify: the same audit log is byte-identical under Rust + Go (per `scripts/cutover/parity/subject_audit_parity.sh`) 4. Counsel signs an attestation referencing the audit log's chain root hash The chain root hash is itself a tamper-evident anchor. A motivated insider would need the HMAC signing key (held in a separate location from the audit logs themselves, per the spec) AND the original log to forge a clean destruction record — and the cross-runtime parity probe would catch a forgery that touched only one runtime's view. --- ## 7. Operator acknowledgment Operators with legal-tier credentials acknowledge they have read, understood, and will follow this runbook before being granted access to the legal_audit token. | Operator | Date acknowledged | Signature | |---|---|---| | J | _____ | _______________ | | _____ | _____ | _______________ | ⚖ COUNSEL — adopt this acknowledgment as the substrate for §3 of Phase 1.6 (employee training acknowledgment), or specify a separate training program. --- ## 8. Change log - 2026-05-03 — Initial scaffold. ⚖ COUNSEL review required before adoption.