Data Protection Audit
You review the data lifecycle from ingestion to destruction. You answer: what data do we have, where does it live, who can reach it, how long does it stick around, and how do we prove any of this.
This skill overlaps deliberately with security-audit (crypto, secrets) and compliance-check (GDPR data-subject rights, retention obligations). The orchestrator dedupes cross-skill — focus on data-specific framings here.
Inputs
From orchestrator: scope_tier, jurisdiction, data_sensitivity, stack_summary, gitnexus_indexed, and the security + compliance findings.
Mode detection
- Plan mode — report gaps with described remediations.
- Edit mode — apply fixes. Encryption at rest changes (enabling TDE, enabling volume encryption) often require migration coordination — require confirmation. Retention cleanup jobs, field-level encryption for new rows, and key rotation automation can often be added safely.
Thresholds by tier
| Tier |
Encryption at rest |
Encryption in transit |
PII inventory |
Retention |
Backups |
| prototype |
advisory |
required (TLS for user-facing) |
advisory |
advisory |
basic |
| team |
required on DB + object storage |
required everywhere |
required |
required + enforced programmatically |
required + tested restore |
| scalable |
required + customer-managed keys for regulated data |
required + internal mTLS for sensitive flows |
required + automated |
required + auditable |
required + cross-region + tested |
Review surface
1. Data classification
You cannot protect what you haven't classified.
- Is there a documented classification scheme? e.g.
public / internal / confidential / restricted.
- Which database columns / object-storage paths / log fields / cache entries fall into each class?
- At scalable tier, classification should be encoded in code: column-level tags (comments, ORM metadata), schema linting rule for new fields, central registry.
Use GitNexus mcp__gitnexus__query to enumerate all schema fields if available. Otherwise parse ORM models / SQL migrations / Prisma schema / Drizzle schema / SQLAlchemy models / Hibernate entities / ActiveRecord migrations.
Check for these often-unclassified PII fields:
- email, phone, name, address, postcode, IP address, device ID, advertising ID, cookie ID, user-agent with other signals.
- date_of_birth, national_id, passport, driver_license, tax_id, SSN.
- payment_method, card_last_four, bank_account, IBAN.
- health_condition, genetic_data, biometric_template, biometric_hash.
- precise geolocation, travel history.
- religion, political opinion, sexual orientation, trade union membership.
- children's data (especially if younger than jurisdiction-specific age of consent).
- free-form text fields that likely contain PII (user-submitted bio, note, message, support ticket body).
2. PII inventory + data flow
- Data flow diagram: where does PII enter, where does it live (DB tables, caches, object storage, logs, analytics pipelines, third-party SaaS), where does it leave?
- Third-party sub-processors: list every external SaaS that receives user data. Cross-reference compliance-check output.
- Copies: dev / staging environments with prod PII? This is a finding unless anonymized.
- Derived data: ML feature stores, analytics warehouses, embedding stores — often overlooked.
3. Encryption at rest
- Database: is disk-level encryption on? (AWS RDS encryption, GCP Cloud SQL encryption, Azure SQL TDE, managed storage encryption). Flag DBs created without encryption at team+ tier.
- Application-level / field-level encryption for extra-sensitive fields (health, payment, government IDs). Look for dedicated crypto libraries:
tink, age, libsodium / NaCl, language wrappers.
- Object storage (S3, GCS, Azure Blob): default encryption enabled? Bucket policies enforce server-side encryption? SSE-KMS rather than SSE-S3 at scalable tier for regulated data?
- Backups: encrypted? Keys distinct from primary storage keys?
- Logs: if logs contain PII (even hashed), the log store must be encrypted with same rigor as primary data.
- Caches: Redis / Memcached / in-memory — at-rest encryption of the cache host disk at team+ tier. Field-level if sensitive.
- Message queues: Kafka / SQS / Pub/Sub — at-rest encryption of broker storage.
- Local dev caches: developers' laptops often accumulate real PII in local SQLite / Redis — flag if prod data syncs to dev.
4. Encryption in transit
Cross-references security-audit's transport checks. Data-protection specifics:
- Internal service-to-service TLS — at scalable tier, east-west traffic should be mTLS, not just plaintext inside a VPC.
- Database connections use TLS with certificate verification (not
sslmode=disable or ?ssl=false).
- Admin / operator access (psql, SSH, bastion) over encrypted channels only.
- Backup transfers over encrypted channels.
- Exports / data subject access responses delivered securely (not unencrypted email attachment).
- Webhooks outbound: HTTPS enforced, endpoint verification (signing).
5. Key management
- Where are encryption keys stored? Not in app config. Use: AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault, Hashicorp Consul, sealed-secrets, or HSM for scalable tier.
- Key rotation:
- Periodic rotation for data-encryption keys (typically 1y).
- Automated rotation preferred over manual.
- Rotation tested? Last rotation date known?
- Key access control: who / what can decrypt?
- Principle of least privilege on key policies.
- Separation of duties: the engineer who writes the code doesn't have direct decrypt access in prod.
- Envelope encryption pattern: data keys encrypted by a master key — avoid bulk-decrypting all data under one compromised key.
- Customer-managed keys (BYOK / CMK) offered at scalable tier for enterprise / regulated customers.
6. Retention
- Documented retention per data class / table:
- How long kept?
- Under what lawful basis (GDPR) / business need?
- How is it deleted?
- Programmatic enforcement: scheduled jobs that actually delete expired data. Flag if "retention" is policy-only with no enforcement.
- Look for cleanup jobs / TTLs:
DELETE FROM ... WHERE created_at < ..., DynamoDB TTL, S3 lifecycle rules, BigQuery partition expiration, Elasticsearch ILM, log retention config.
- Soft delete vs. hard delete: user expects "delete my account" to actually delete. If soft-delete, is there a hard-delete sweeper?
- Backups: retention of backups containing deleted records. Crypto-shredding (destroying keys) can satisfy this where backup deletion is infeasible.
- Audit logs: retained at least as long as any compliance obligation, but not indefinitely without cause.
7. Right to erasure (overlap with compliance-check)
For each data store, when user exercises erasure:
- Primary DB: row deleted or field-cleared?
- Derived stores: analytics warehouse, feature store, embeddings, ML models trained on user data — handled?
- Logs: tagged with user ID so logs can be deleted or pseudonymized?
- Backups: policy exists; crypto-shredding if immediate deletion impossible.
- Third-party processors: delete request propagated.
- Caches: invalidated.
8. Anonymization and pseudonymization
- Pseudonymization (reversible with a separate key): check for tokenization / hashing with pepper / reversible encryption where used.
- Pseudonymization alone is not anonymization under GDPR — still personal data.
- Anonymization (irreversible): k-anonymity, l-diversity, differential privacy where analytics on PII is required.
- "Hashing the email" is not anonymization — easily reversed via rainbow table + dictionary.
- Dev/staging data: anonymize or synthesize. Do not copy prod PII into dev.
9. Data residency
- Where is each class of data stored?
- Where is it processed (including transient)?
- Regulatory requirements (e.g. some EU public-sector data must stay in EU)?
- For CDNs / edge functions: do they cache PII outside allowed regions?
- Sub-processors: their regions matter too — check their Trust Center / DPA.
10. Backups
- Exist: how often, what RPO, what RTO?
- Encrypted: see §3.
- Restore tested: a backup you haven't restored is schrödinger's backup. Flag if restore hasn't been tested in the last 6 months at team+ tier, quarterly at scalable.
- Off-site / cross-region: at scalable tier, backups in a different region than primary.
- Immutable / append-only backups at scalable tier for ransomware resilience.
- Retention windows balance recoverability vs. compliance obligations.
11. Access control to data
- Who has direct DB access in production? List by role; confirm principle of least privilege.
- Break-glass procedures documented; regular access limited to read-only where possible.
- Query logging for admin queries on sensitive tables.
- Just-in-time access at scalable tier (Teleport, Boundary, CyberArk, Okta JIT).
- Row-level security or tenant isolation for multi-tenant apps — check it's enforced at the DB layer, not only in app code.
12. Data minimization
For every collected field, can you justify it?
- Why is this collected?
- Who uses it?
- How long kept?
If answers are "we might need it someday", it's over-collection. Trim.
At scalable tier, new fields should require a review gate (schema review, DPIA triggers).
13. Data export / portability
- GDPR Art. 20 requires machine-readable export (cross-reference compliance-check).
- Export process:
- Includes all data, across all stores?
- Format (JSON, CSV) is reasonably machine-readable?
- Delivery mechanism is secure (authenticated download link, not plain email)?
- Rate-limited to prevent enumeration / scraping via repeated export?
14. Cross-border transfers
- Any data leaving home jurisdiction?
- Lawful transfer mechanism? (SCCs, adequacy, BCR for EU; APEC CBPR; etc.)
- Transfer impact assessment documented for EU→US after Schrems II (for EU data).
15. Telemetry and analytics
- Frontend analytics (GA, Mixpanel, Amplitude, Segment, PostHog): what's collected?
- IP addresses recorded? Masked / truncated?
- Device fingerprinting?
- Consent gate before loading analytics scripts (for EU)?
Severity classification
| Severity |
Meaning |
| critical |
Large-scale unencrypted sensitive data. No ability to delete on request. Prod PII in dev. No backups or untested ones for a team+ tier system. |
| high |
At-rest encryption missing for PII. No retention enforcement. Keys co-located with data they protect. |
| medium |
Field-level encryption missing for sensitive fields. Retention policy exists but only in docs. |
| low |
Nice-to-have: customer-managed keys, differential privacy, immutable backups. |
| info |
Inventory observations. |
Output format
- id: DATA-<NNN>
severity: ...
category: classification | encryption-rest | encryption-transit | keys | retention | erasure | anonymization | residency | backups | access | minimization | portability | transfers | telemetry
title: ...
location: <file or system-level>
description: |
<what, why, realistic exposure scenario>
evidence:
- <schema snippet / config snippet / gitnexus finding>
remediation:
plan_mode: |
<fix description>
edit_mode: |
<code / config diff>
references:
- <GDPR article / ENISA guideline / NIST SP>
blocker_at_tier: [...]
data_classes_affected: [email, health_record, ...]
Dimension summary:
## Data Protection Summary
Data classes inventoried: <count>
Sensitive fields identified: <list>
Stores covered: <DB, object-storage, cache, queue, logs, warehouse, ...>
Encryption at rest: <status per store>
Encryption in transit: <status>
Retention enforced: <yes/no per data class>
Backup last tested restore: <date or unknown>
Top 3 data-protection risks:
1. ...
Example findings
Example 1 — Production PII copied to developer laptops
- id: DATA-002
severity: critical
category: access
title: "Developers sync prod DB dumps to local via `rake db:pull`"
location: "Rakefile:67; process-level"
description: |
The repo includes a `rake db:pull` task that snapshots the
production DB to the running developer's laptop for debugging.
Interviewed engineers confirmed it's used ~weekly. Production
`users` includes names, emails, phone numbers, and
government-issued ID fragments for ~300k users; `transactions`
includes payment metadata. This is a GDPR Art. 5 and Art. 32
finding (data minimization and security of processing
respectively), a PCI-DSS scope explosion (every developer laptop
is now in scope if payment data is touched), and a breach waiting
for a lost/stolen laptop.
evidence:
- |
# Rakefile:67
task :db_pull do
sh "pg_dump $PROD_URL > db/dev.sql"
sh "psql $DEV_URL < db/dev.sql"
end
remediation:
plan_mode: |
1. Remove the task. Replace with a synthetic-data generator or
a manually-anonymized staging snapshot pipeline (pg_anonymizer,
Tonic, or custom masking) that runs server-side and is never
copied to laptops.
2. Revoke prod DB credentials from developers; use Teleport /
JIT access for read-only diagnostic queries with audit.
3. Add a pre-commit hook to block commits that contain
high-entropy strings suggestive of prod data.
edit_mode: |
Delete the Rake task. Scaffold `scripts/synth_data.py` and
`db/anonymize.sql`. Requires confirmation and ops coordination
for credential revocation.
references:
- "Regulation (EU) 2016/679 Art. 5(1)(c), 32"
related_findings: [COMP-012]
blocker_at_tier: [team, scalable]
Example 2 — Backups unencrypted
- id: DATA-008
severity: high
category: backups
title: "Nightly DB backup stored in S3 bucket without server-side encryption"
location: "infra/terraform/backup.tf:22"
description: |
The backup bucket has no default encryption configured — objects
land unencrypted unless the client explicitly sets
`ServerSideEncryption`. The backup job uses `aws s3 cp` with no
SSE flag. Backups contain the full user + transactions tables.
AWS introduced default SSE in 2023, but Terraform older than that
with an explicit bucket config overrides it. Unencrypted backups
are a finding under GDPR Art. 32 and a clear regulatory gap for
HIPAA-covered or PCI-DSS-in-scope data.
evidence:
- |
# infra/terraform/backup.tf:22 — missing server_side_encryption block
resource "aws_s3_bucket" "backups" {
bucket = "acme-prod-backups"
}
remediation:
plan_mode: |
1. Add `aws_s3_bucket_server_side_encryption_configuration` to
force SSE-KMS (preferred) or SSE-S3 on every object.
2. Use a dedicated KMS key for backups (rotation enabled),
different from application-layer keys — enables crypto-
shredding without affecting live data.
3. Bucket policy denies unencrypted uploads.
4. Re-upload existing unencrypted objects to force encryption.
edit_mode: |
Safe with one caveat: a subsequent sweep job re-encrypts existing
objects (costs GB-transferred pricing). Confirm before applying.
references:
- "Regulation (EU) 2016/679 Art. 32"
- "AWS S3 User Guide — Default encryption"
blocker_at_tier: [team, scalable]
data_classes_affected: [email, name, phone, transaction]
Example 3 — Retention policy documented but never enforced
- id: DATA-016
severity: high
category: retention
title: "6-year audit-log retention documented; no scheduled deletion job"
location: "docs/privacy-policy.md; system-level"
description: |
The privacy policy states audit logs retained 6 years for tax +
compliance reasons, then deleted. The policy is a public
commitment to data subjects and supervisory authorities. In fact,
no scheduled deletion job exists — `audit_log` has rows dating to
2018 (oldest 7.5 years), ~112M rows, 180 GB. The mismatch is
itself a GDPR Art. 5(1)(e) finding (storage limitation). It's also
a supervisor-provokable question if a data subject requests
confirmation that their data has been deleted.
evidence:
- "docs/privacy-policy.md §7: 'We retain audit logs for 6 years.'"
- "SELECT MIN(created_at) FROM audit_log → 2018-04-11"
remediation:
plan_mode: |
1. Add a scheduled job (daily or weekly) that deletes / archives
rows beyond the documented window.
2. Chunked delete to avoid long locks on the table.
3. Log the deletion counts to the audit stream itself (deleted N
rows from window Y).
4. One-time backfill: delete pre-policy rows in a managed
migration with ops awareness.
edit_mode: |
Destructive. Requires explicit confirmation and legal sign-off
before first run — some categories may have overriding legal
retention (tax, fraud investigations).
references:
- "Regulation (EU) 2016/679 Art. 5(1)(e)"
related_findings: [COMP-018]
blocker_at_tier: [team, scalable]
data_classes_affected: [audit_log]
Edit-mode remediation
Safe to apply:
- Adding retention cleanup jobs (scheduled delete) — but confirm retention period with user.
- Enabling
sslmode=require / ssl=true on DB clients (if server supports it).
- Adding TTLs to caches.
- Adding S3 bucket default-encryption config.
- Adding S3 lifecycle rules for log retention.
- Scrubbing known-PII fields from logs at the logger level.
- Adding PII column comments / annotations for inventory tracking.
Require confirmation per change:
- Enabling DB-level encryption on an existing database (may require downtime / re-write).
- Adding field-level encryption to existing columns (needs backfill strategy).
- Rotating encryption keys (needs coordination with backups + active sessions).
- Deleting data (anything that destroys data needs explicit approval even if called "retention cleanup").
- Changing backup / restore configuration.
- Changing access control on data stores.
Do not
- Do not treat hashing as encryption. Hashes are one-way, but hashes of bounded values (emails, phone numbers) are trivially reversible.
- Do not treat pseudonymization as anonymization.
- Do not recommend "encrypt everything" as a universal fix — crypto creates new problems (key management, recoverability) and adds latency. Match control to data class.
- Do not ignore dev/staging — prod PII in dev is one of the most common compliance findings.
- Do not silently delete data, even when "policy says so". Log, confirm, leave an audit trail.
- Do not confuse at-rest encryption at the disk layer with protection from the application — if the app is compromised, disk encryption doesn't help.
- Do not conflate backup with archive. Backup = restore a recent state. Archive = long-term retention. They have different requirements.
1---2name: data-protection-audit3description: Reviews how data is classified, stored, transmitted, retained, and destroyed. Covers encryption at rest and in transit, PII classification and inventory, retention and deletion policies, data residency, key management, backup integrity, and anonymization / pseudonymization. Use when the user asks about "data protection", "encryption", "PII", "data retention", "key management", "backups", invokes /data-protection-audit, or when the orchestrator delegates. Stack-agnostic, mode-aware, scope-tier-aware.4license: Apache-2.05---67# Data Protection Audit89You review the data lifecycle from ingestion to destruction. You answer: *what data do we have, where does it live, who can reach it, how long does it stick around, and how do we prove any of this*.1011This skill overlaps deliberately with `security-audit` (crypto, secrets) and `compliance-check` (GDPR data-subject rights, retention obligations). The orchestrator dedupes cross-skill — focus on data-specific framings here.1213## Inputs1415From orchestrator: `scope_tier`, `jurisdiction`, `data_sensitivity`, `stack_summary`, `gitnexus_indexed`, and the security + compliance findings.1617## Mode detection1819- **Plan mode** — report gaps with described remediations.20- **Edit mode** — apply fixes. Encryption at rest changes (enabling TDE, enabling volume encryption) often require migration coordination — require confirmation. Retention cleanup jobs, field-level encryption for new rows, and key rotation automation can often be added safely.2122## Thresholds by tier2324| Tier | Encryption at rest | Encryption in transit | PII inventory | Retention | Backups |25|---|---|---|---|---|---|26| prototype | advisory | required (TLS for user-facing) | advisory | advisory | basic |27| team | **required** on DB + object storage | **required** everywhere | **required** | **required + enforced programmatically** | **required + tested restore** |28| scalable | **required + customer-managed keys** for regulated data | **required + internal mTLS** for sensitive flows | **required + automated** | **required + auditable** | **required + cross-region + tested** |2930## Review surface3132### 1. Data classification3334**You cannot protect what you haven't classified.**3536- Is there a documented classification scheme? e.g. `public / internal / confidential / restricted`.37- Which database columns / object-storage paths / log fields / cache entries fall into each class?38- At scalable tier, classification should be encoded in code: column-level tags (comments, ORM metadata), schema linting rule for new fields, central registry.3940Use GitNexus `mcp__gitnexus__query` to enumerate all schema fields if available. Otherwise parse ORM models / SQL migrations / Prisma schema / Drizzle schema / SQLAlchemy models / Hibernate entities / ActiveRecord migrations.4142**Check for these often-unclassified PII fields:**43- email, phone, name, address, postcode, IP address, device ID, advertising ID, cookie ID, user-agent with other signals.44- date_of_birth, national_id, passport, driver_license, tax_id, SSN.45- payment_method, card_last_four, bank_account, IBAN.46- health_condition, genetic_data, biometric_template, biometric_hash.47- precise geolocation, travel history.48- religion, political opinion, sexual orientation, trade union membership.49- children's data (especially if younger than jurisdiction-specific age of consent).50- free-form text fields that likely contain PII (user-submitted bio, note, message, support ticket body).5152### 2. PII inventory + data flow5354- **Data flow diagram**: where does PII enter, where does it live (DB tables, caches, object storage, logs, analytics pipelines, third-party SaaS), where does it leave?55- **Third-party sub-processors**: list every external SaaS that receives user data. Cross-reference compliance-check output.56- **Copies**: dev / staging environments with prod PII? This is a finding unless anonymized.57- **Derived data**: ML feature stores, analytics warehouses, embedding stores — often overlooked.5859### 3. Encryption at rest6061- **Database**: is disk-level encryption on? (AWS RDS encryption, GCP Cloud SQL encryption, Azure SQL TDE, managed storage encryption). Flag DBs created without encryption at team+ tier.62- **Application-level / field-level encryption** for extra-sensitive fields (health, payment, government IDs). Look for dedicated crypto libraries: `tink`, `age`, `libsodium` / `NaCl`, language wrappers.63- **Object storage** (S3, GCS, Azure Blob): default encryption enabled? Bucket policies enforce server-side encryption? SSE-KMS rather than SSE-S3 at scalable tier for regulated data?64- **Backups**: encrypted? Keys distinct from primary storage keys?65- **Logs**: if logs contain PII (even hashed), the log store must be encrypted with same rigor as primary data.66- **Caches**: Redis / Memcached / in-memory — at-rest encryption of the cache host disk at team+ tier. Field-level if sensitive.67- **Message queues**: Kafka / SQS / Pub/Sub — at-rest encryption of broker storage.68- **Local dev caches**: developers' laptops often accumulate real PII in local SQLite / Redis — flag if prod data syncs to dev.6970### 4. Encryption in transit7172Cross-references security-audit's transport checks. Data-protection specifics:7374- **Internal service-to-service TLS** — at scalable tier, east-west traffic should be mTLS, not just plaintext inside a VPC.75- **Database connections** use TLS with certificate verification (not `sslmode=disable` or `?ssl=false`).76- **Admin / operator access** (psql, SSH, bastion) over encrypted channels only.77- **Backup transfers** over encrypted channels.78- **Exports / data subject access responses** delivered securely (not unencrypted email attachment).79- **Webhooks outbound**: HTTPS enforced, endpoint verification (signing).8081### 5. Key management8283- **Where are encryption keys stored?** Not in app config. Use: AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault, Hashicorp Consul, sealed-secrets, or HSM for scalable tier.84- **Key rotation**:85 - Periodic rotation for data-encryption keys (typically 1y).86 - Automated rotation preferred over manual.87 - Rotation tested? Last rotation date known?88- **Key access control**: who / what can decrypt?89 - Principle of least privilege on key policies.90 - Separation of duties: the engineer who writes the code doesn't have direct decrypt access in prod.91- **Envelope encryption** pattern: data keys encrypted by a master key — avoid bulk-decrypting all data under one compromised key.92- **Customer-managed keys (BYOK / CMK)** offered at scalable tier for enterprise / regulated customers.9394### 6. Retention9596- **Documented retention per data class / table**:97 - How long kept?98 - Under what lawful basis (GDPR) / business need?99 - How is it deleted?100- **Programmatic enforcement**: scheduled jobs that actually delete expired data. Flag if "retention" is policy-only with no enforcement.101- Look for cleanup jobs / TTLs: `DELETE FROM ... WHERE created_at < ...`, DynamoDB TTL, S3 lifecycle rules, BigQuery partition expiration, Elasticsearch ILM, log retention config.102- **Soft delete vs. hard delete**: user expects "delete my account" to actually delete. If soft-delete, is there a hard-delete sweeper?103- **Backups**: retention of backups containing deleted records. Crypto-shredding (destroying keys) can satisfy this where backup deletion is infeasible.104- **Audit logs**: retained *at least* as long as any compliance obligation, but not indefinitely without cause.105106### 7. Right to erasure (overlap with compliance-check)107108For each data store, when user exercises erasure:109110- Primary DB: row deleted or field-cleared?111- Derived stores: analytics warehouse, feature store, embeddings, ML models trained on user data — handled?112- Logs: tagged with user ID so logs can be deleted or pseudonymized?113- Backups: policy exists; crypto-shredding if immediate deletion impossible.114- Third-party processors: delete request propagated.115- Caches: invalidated.116117### 8. Anonymization and pseudonymization118119- **Pseudonymization** (reversible with a separate key): check for tokenization / hashing with pepper / reversible encryption where used.120 - Pseudonymization alone is not anonymization under GDPR — still personal data.121- **Anonymization** (irreversible): k-anonymity, l-diversity, differential privacy where analytics on PII is required.122 - "Hashing the email" is not anonymization — easily reversed via rainbow table + dictionary.123- **Dev/staging data**: anonymize or synthesize. Do not copy prod PII into dev.124125### 9. Data residency126127- Where is each class of data **stored**?128- Where is it **processed** (including transient)?129- Regulatory requirements (e.g. some EU public-sector data must stay in EU)?130- For CDNs / edge functions: do they cache PII outside allowed regions?131- **Sub-processors**: their regions matter too — check their Trust Center / DPA.132133### 10. Backups134135- **Exist**: how often, what RPO, what RTO?136- **Encrypted**: see §3.137- **Restore tested**: a backup you haven't restored is schrödinger's backup. Flag if restore hasn't been tested in the last 6 months at team+ tier, quarterly at scalable.138- **Off-site / cross-region**: at scalable tier, backups in a different region than primary.139- **Immutable / append-only backups** at scalable tier for ransomware resilience.140- **Retention windows** balance recoverability vs. compliance obligations.141142### 11. Access control to data143144- **Who has direct DB access in production?** List by role; confirm principle of least privilege.145- **Break-glass procedures** documented; regular access limited to read-only where possible.146- **Query logging** for admin queries on sensitive tables.147- **Just-in-time access** at scalable tier (Teleport, Boundary, CyberArk, Okta JIT).148- **Row-level security** or tenant isolation for multi-tenant apps — check it's enforced at the DB layer, not only in app code.149150### 12. Data minimization151152For every collected field, can you justify it?153- **Why is this collected?**154- **Who uses it?**155- **How long kept?**156157If answers are "we might need it someday", it's over-collection. Trim.158159At scalable tier, new fields should require a review gate (schema review, DPIA triggers).160161### 13. Data export / portability162163- GDPR Art. 20 requires machine-readable export (cross-reference compliance-check).164- Export process:165 - Includes all data, across all stores?166 - Format (JSON, CSV) is reasonably machine-readable?167 - Delivery mechanism is secure (authenticated download link, not plain email)?168 - Rate-limited to prevent enumeration / scraping via repeated export?169170### 14. Cross-border transfers171172- Any data leaving home jurisdiction?173- Lawful transfer mechanism? (SCCs, adequacy, BCR for EU; APEC CBPR; etc.)174- Transfer impact assessment documented for EU→US after Schrems II (for EU data).175176### 15. Telemetry and analytics177178- Frontend analytics (GA, Mixpanel, Amplitude, Segment, PostHog): what's collected?179- IP addresses recorded? Masked / truncated?180- Device fingerprinting?181- Consent gate before loading analytics scripts (for EU)?182183## Severity classification184185| Severity | Meaning |186|---|---|187| critical | Large-scale unencrypted sensitive data. No ability to delete on request. Prod PII in dev. No backups or untested ones for a team+ tier system. |188| high | At-rest encryption missing for PII. No retention enforcement. Keys co-located with data they protect. |189| medium | Field-level encryption missing for sensitive fields. Retention policy exists but only in docs. |190| low | Nice-to-have: customer-managed keys, differential privacy, immutable backups. |191| info | Inventory observations. |192193## Output format194195```yaml196- id: DATA-<NNN>197 severity: ...198 category: classification | encryption-rest | encryption-transit | keys | retention | erasure | anonymization | residency | backups | access | minimization | portability | transfers | telemetry199 title: ...200 location: <file or system-level>201 description: |202 <what, why, realistic exposure scenario>203 evidence:204 - <schema snippet / config snippet / gitnexus finding>205 remediation:206 plan_mode: |207 <fix description>208 edit_mode: |209 <code / config diff>210 references:211 - <GDPR article / ENISA guideline / NIST SP>212 blocker_at_tier: [...]213 data_classes_affected: [email, health_record, ...]214```215216Dimension summary:217218```markdown219## Data Protection Summary220221Data classes inventoried: <count>222Sensitive fields identified: <list>223Stores covered: <DB, object-storage, cache, queue, logs, warehouse, ...>224Encryption at rest: <status per store>225Encryption in transit: <status>226Retention enforced: <yes/no per data class>227Backup last tested restore: <date or unknown>228229Top 3 data-protection risks:230 1. ...231```232233## Example findings234235### Example 1 — Production PII copied to developer laptops236237```yaml238- id: DATA-002239 severity: critical240 category: access241 title: "Developers sync prod DB dumps to local via `rake db:pull`"242 location: "Rakefile:67; process-level"243 description: |244 The repo includes a `rake db:pull` task that snapshots the245 production DB to the running developer's laptop for debugging.246 Interviewed engineers confirmed it's used ~weekly. Production247 `users` includes names, emails, phone numbers, and248 government-issued ID fragments for ~300k users; `transactions`249 includes payment metadata. This is a GDPR Art. 5 and Art. 32250 finding (data minimization and security of processing251 respectively), a PCI-DSS scope explosion (every developer laptop252 is now in scope if payment data is touched), and a breach waiting253 for a lost/stolen laptop.254 evidence:255 - |256 # Rakefile:67257 task :db_pull do258 sh "pg_dump $PROD_URL > db/dev.sql"259 sh "psql $DEV_URL < db/dev.sql"260 end261 remediation:262 plan_mode: |263 1. Remove the task. Replace with a synthetic-data generator or264 a manually-anonymized staging snapshot pipeline (pg_anonymizer,265 Tonic, or custom masking) that runs server-side and is never266 copied to laptops.267 2. Revoke prod DB credentials from developers; use Teleport /268 JIT access for read-only diagnostic queries with audit.269 3. Add a pre-commit hook to block commits that contain270 high-entropy strings suggestive of prod data.271 edit_mode: |272 Delete the Rake task. Scaffold `scripts/synth_data.py` and273 `db/anonymize.sql`. Requires confirmation and ops coordination274 for credential revocation.275 references:276 - "Regulation (EU) 2016/679 Art. 5(1)(c), 32"277 related_findings: [COMP-012]278 blocker_at_tier: [team, scalable]279```280281### Example 2 — Backups unencrypted282283```yaml284- id: DATA-008285 severity: high286 category: backups287 title: "Nightly DB backup stored in S3 bucket without server-side encryption"288 location: "infra/terraform/backup.tf:22"289 description: |290 The backup bucket has no default encryption configured — objects291 land unencrypted unless the client explicitly sets292 `ServerSideEncryption`. The backup job uses `aws s3 cp` with no293 SSE flag. Backups contain the full user + transactions tables.294 AWS introduced default SSE in 2023, but Terraform older than that295 with an explicit bucket config overrides it. Unencrypted backups296 are a finding under GDPR Art. 32 and a clear regulatory gap for297 HIPAA-covered or PCI-DSS-in-scope data.298 evidence:299 - |300 # infra/terraform/backup.tf:22 — missing server_side_encryption block301 resource "aws_s3_bucket" "backups" {302 bucket = "acme-prod-backups"303 }304 remediation:305 plan_mode: |306 1. Add `aws_s3_bucket_server_side_encryption_configuration` to307 force SSE-KMS (preferred) or SSE-S3 on every object.308 2. Use a dedicated KMS key for backups (rotation enabled),309 different from application-layer keys — enables crypto-310 shredding without affecting live data.311 3. Bucket policy denies unencrypted uploads.312 4. Re-upload existing unencrypted objects to force encryption.313 edit_mode: |314 Safe with one caveat: a subsequent sweep job re-encrypts existing315 objects (costs GB-transferred pricing). Confirm before applying.316 references:317 - "Regulation (EU) 2016/679 Art. 32"318 - "AWS S3 User Guide — Default encryption"319 blocker_at_tier: [team, scalable]320 data_classes_affected: [email, name, phone, transaction]321```322323### Example 3 — Retention policy documented but never enforced324325```yaml326- id: DATA-016327 severity: high328 category: retention329 title: "6-year audit-log retention documented; no scheduled deletion job"330 location: "docs/privacy-policy.md; system-level"331 description: |332 The privacy policy states audit logs retained 6 years for tax +333 compliance reasons, then deleted. The policy is a public334 commitment to data subjects and supervisory authorities. In fact,335 no scheduled deletion job exists — `audit_log` has rows dating to336 2018 (oldest 7.5 years), ~112M rows, 180 GB. The mismatch is337 itself a GDPR Art. 5(1)(e) finding (storage limitation). It's also338 a supervisor-provokable question if a data subject requests339 confirmation that their data has been deleted.340 evidence:341 - "docs/privacy-policy.md §7: 'We retain audit logs for 6 years.'"342 - "SELECT MIN(created_at) FROM audit_log → 2018-04-11"343 remediation:344 plan_mode: |345 1. Add a scheduled job (daily or weekly) that deletes / archives346 rows beyond the documented window.347 2. Chunked delete to avoid long locks on the table.348 3. Log the deletion counts to the audit stream itself (deleted N349 rows from window Y).350 4. One-time backfill: delete pre-policy rows in a managed351 migration with ops awareness.352 edit_mode: |353 Destructive. Requires explicit confirmation and legal sign-off354 before first run — some categories may have overriding legal355 retention (tax, fraud investigations).356 references:357 - "Regulation (EU) 2016/679 Art. 5(1)(e)"358 related_findings: [COMP-018]359 blocker_at_tier: [team, scalable]360 data_classes_affected: [audit_log]361```362363## Edit-mode remediation364365Safe to apply:366- Adding retention cleanup jobs (scheduled delete) — but confirm retention period with user.367- Enabling `sslmode=require` / `ssl=true` on DB clients (if server supports it).368- Adding TTLs to caches.369- Adding S3 bucket default-encryption config.370- Adding S3 lifecycle rules for log retention.371- Scrubbing known-PII fields from logs at the logger level.372- Adding PII column comments / annotations for inventory tracking.373374Require confirmation per change:375- Enabling DB-level encryption on an existing database (may require downtime / re-write).376- Adding field-level encryption to existing columns (needs backfill strategy).377- Rotating encryption keys (needs coordination with backups + active sessions).378- Deleting data (anything that destroys data needs explicit approval even if called "retention cleanup").379- Changing backup / restore configuration.380- Changing access control on data stores.381382## Do not383384- Do not treat hashing as encryption. Hashes are one-way, but hashes of bounded values (emails, phone numbers) are trivially reversible.385- Do not treat pseudonymization as anonymization.386- Do not recommend "encrypt everything" as a universal fix — crypto creates new problems (key management, recoverability) and adds latency. Match control to data class.387- Do not ignore dev/staging — prod PII in dev is one of the most common compliance findings.388- Do not silently delete data, even when "policy says so". Log, confirm, leave an audit trail.389- Do not confuse at-rest encryption at the disk layer with protection from the application — if the app is compromised, disk encryption doesn't help.390- Do not conflate backup with archive. Backup = restore a recent state. Archive = long-term retention. They have different requirements.