data-privacy
Skill26 starsChanged 6 months agoMITView on GitHub
Use when the user stores user data, PII, payment info, health/biometric data, builds export/delete features, signs up for data processors, configures backups, or designs cross-border data flows. Covers encryption at rest/transit, deletion paths, audit logs, what to never log, and minimum-data principles.
3 other projects use a version of this.
Adopted by
Most recently taken up by
- pradyumnasagar/open-research-skillstheir own version, first seen Nov 8, 2026
- novatic-cu/nova-skillstheir own version, first seen Sep 20, 2026
- RiskResponse/ciso-security-skillstheir own version, first seen Feb 8, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- pradyumnasagar/open-research-skills★ 8same name
- RiskResponse/ciso-security-skills★ 8same name
- novatic-cu/nova-skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository19 other files it gives its agents.
- api-route-hardeningSkill
- auth-and-sessionsSkill
- authorizationSkill
- caching-and-invalidationSkill
- database-query-safetySkill
- error-handlingSkill
- file-uploadsSkill
- input-validationSkill
- jobs-and-queuesSkill
- llm-endpoint-safetySkill
- migrations-and-schemaSkill
- observabilitySkill
- production-readinessSkill
- reliability-patternsSkill
- rsc-boundariesSkill
- secrets-and-envSkill
- testing-strategySkill
- transactions-and-consistencySkill
- webhooksSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
20 rules. 0 are common, 20 are distinctive, and 0 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
20
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 20
No user-attributable data (truly public, anonymous content)
- Distinctive: line 30
Every field you ask for is a liability.
- Distinctive: line 68
Use a managed KMS (AWS KMS, GCP KMS, Cloud HSM) for the key.
- Distinctive: line 72
If you only need to check "does this email exist in our system?", you may not need to *store* the email — store a hash for comparison.
- Distinctive: line 80
If you must handle card data: full PCI DSS audit, ASV scans, network segmentation.
- Distinctive: line 100
When something goes wrong (or a regulator asks), you can answer "who looked at this?" Audit logs go to a different store, with different …
- Distinctive: line 108
Delete from search indexes (Algolia, Meilisearch, OpenSearch)
- Distinctive: line 109
Delete from caches (Redis, CDN)
- Distinctive: line 110
Delete from analytics if scoped to identity (PostHog, Amplitude)
- Distinctive: line 111
Delete from emails-out-of-band (transactional providers retain logs)
- Distinctive: line 112
Delete from backups eventually (or document retention period clearly)
- Distinctive: line 113
Delete from logs (or set TTL such that logs age out)
- Distinctive: line 116
Test the path end-to-end before launch.
- Distinctive: line 139
Document sub-processors and where each holds data (Stripe, Resend, Vercel, Upstash, etc.)
- Distinctive: line 141
If you have any EU users: a Data Processing Addendum (DPA) is the table-stakes contract.
- Distinctive: line 146
Document a clear retention window for backups (e.g., 30 days), so deleted data ages out predictably
- Distinctive: line 147
Use point-in-time recovery with deletion-at-PITR-window logic
- Distinctive: line 150
Don't keep backups forever.
- Distinctive: line 154
Every SaaS you send user data to (Stripe, OpenAI, Resend, Datadog, PostHog, Sentry, Cloudflare) is a sub-processor in privacy terms.
- Distinctive: line 161
If your privacy policy doesn't list them, your privacy policy is wrong.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Data Handling & Privacy
Every piece of user data you store is a liability. The cheapest data is the data you didn't collect; the second cheapest is the data you deleted on schedule.
When to use
- Designing a new schema that stores user-attributable data
- Adding a "store this preference / address / payment / message" feature
- Building data export ("download my data")
- Building data deletion ("delete my account")
- Reviewing what gets logged (see
observability) - Picking a third-party processor (sub-processors get your data too)
- Working with PII, PHI, payment data, biometrics, location, minors' data
When to skip
- No user-attributable data (truly public, anonymous content)
The mental model
Data has a lifecycle: collect → store → use → share → retain → delete. Privacy work is making each stage deliberate. "We collected it because the form had a field" is not a reason. "We retain it because we never thought about it" is the most common reason data leaks.
The rules
1. Minimize. Don't collect what you don't need.
Every field you ask for is a liability. Birth date for a B2B SaaS? Probably not. Phone for a free-tier user? Only if you're going to call them.
// BAD — full address for a digital-only product
const Profile = z.object({
fullName: z.string(),
street: z.string(),
city: z.string(),
state: z.string(),
zip: z.string(),
dob: z.string(),
})
// GOOD — collect what the product needs
const Profile = z.object({
displayName: z.string(),
email: z.string().email(),
})2. Encrypt in transit. Always.
https only. HSTS. Modern TLS. No exceptions for "internal" traffic that crosses the public internet (Vercel ↔ Supabase ↔ Upstash all cross networks).
For internal service-to-service, use mTLS or signed requests. "We're inside the VPC" is not encryption.
3. Encrypt at rest. Application-level for sensitive fields.
Disk-level encryption (Postgres TDE, AWS RDS encryption) protects against stolen disks. It does nothing against a compromised app or DB credential — the DB decrypts transparently for any authenticated query.
For high-sensitivity fields (SSNs, government IDs, health data, full PII), encrypt at the application layer:
// Encrypted column: stored as ciphertext, decrypted only by the app with the key
const encrypted = await encrypt(ssn, env.PII_DATA_KEY)
await db.user.update({ data: { ssnEncrypted: encrypted } })Use a managed KMS (AWS KMS, GCP KMS, Cloud HSM) for the key. Rotate it.
4. Hash, don't encrypt, when you only need to compare.
If you only need to check "does this email exist in our system?", you may not need to store the email — store a hash for comparison. Same for IP addresses kept for abuse detection: hash them with a per-tenant salt.
For passwords specifically: argon2id (see auth-and-sessions). Never reversible.
5. PCI: don't touch card data unless you have to.
For payment forms, use Stripe Elements / Checkout / Payment Sheet — your servers never see the PAN. The card data flows browser → Stripe directly; you receive a token. This is the difference between "we follow some PCI rules" and "we're 99% out of scope."
If you must handle card data: full PCI DSS audit, ASV scans, network segmentation. Almost never the right answer for a startup.
6. Audit log every access to sensitive data.
Who, what, when, why. Append-only. Tamper-evident if possible.
await db.auditLog.create({
data: {
actorUserId: session.userId,
action: 'export_users',
resourceType: 'user',
resourceId: targetUserId,
metadata: { reason: req.body.reason },
ip: hashIp(req.ip),
at: new Date(),
},
})When something goes wrong (or a regulator asks), you can answer "who looked at this?" Audit logs go to a different store, with different access, ideally write-only from the app.
7. The deletion rule: actually delete. Or have a real reason not to.
GDPR Article 17, CCPA, and most regional laws give users a right to deletion. "Soft-delete forever" is not deletion — it's hiding.
Deletion path:
- Hard-delete from primary DB (or anonymize: replace PII with
[deleted], keep the row's referential shell if other systems depend on its ID) - Delete from search indexes (Algolia, Meilisearch, OpenSearch)
- Delete from caches (Redis, CDN)
- Delete from analytics if scoped to identity (PostHog, Amplitude)
- Delete from emails-out-of-band (transactional providers retain logs)
- Delete from backups eventually (or document retention period clearly)
- Delete from logs (or set TTL such that logs age out)
- Tell sub-processors who hold the data downstream
Test the path end-to-end before launch.
8. Export rule: structured, machine-readable, complete.
A user export is JSON / CSV / a zip — usable, not "log into a portal." Include everything user-attributable: profile, content, settings, audit log they're entitled to. Don't include other users' data even if it's adjacent (a comment on someone else's post mentions them, redact).
9. Logs are PII. Default to redacting.
What never goes in logs:
- Passwords (obvious; surprisingly common)
- Bearer tokens, API keys, session cookies — strip from
headers - Full request bodies on
POSTto auth/payment endpoints - Email addresses unless redacted (
u***@d***.com) or explicitly required for the log's purpose - Full names, phone numbers, addresses, government IDs — never
Configure redaction at the logger level (Pino redact, Logtape filter), not per-call. See observability.
10. Cross-border data: know where the bytes live.
GDPR (EU), Schrems II (EU↔US), UK DPA, Brazil LGPD, India DPDP, China PIPL — each restricts where personal data can be stored or transferred. Practically:
- Pick a primary region for storage (
eu-west-1,us-east-1) - Pin databases / caches / file storage to that region
- For users in restricted regions, ensure the data path stays within the region (data residency)
- Document sub-processors and where each holds data (Stripe, Resend, Vercel, Upstash, etc.)
If you have any EU users: a Data Processing Addendum (DPA) is the table-stakes contract. Most processors offer one — sign it.
11. Backups are data too.
A "delete my account" that doesn't reach backups is a partial deletion. Either:
- Document a clear retention window for backups (e.g., 30 days), so deleted data ages out predictably
- Use point-in-time recovery with deletion-at-PITR-window logic
- Encrypt backups with a separate key; rotation effectively expires old backups
Don't keep backups forever. "Just in case" is a privacy violation.
12. Treat third-party processors as your data plane.
Every SaaS you send user data to (Stripe, OpenAI, Resend, Datadog, PostHog, Sentry, Cloudflare) is a sub-processor in privacy terms. Audit:
- What data they receive
- What region they store in
- Their retention policy
- Their breach-notification SLA
- Whether you've signed a DPA
If your privacy policy doesn't list them, your privacy policy is wrong.
Specific data classes that earn extra care
| Class | Notes |
| Health (PHI) | HIPAA in US; specific BAAs with processors; minimal logging |
| Children's data | COPPA in US; consent flows; no behavioral ads |
| Biometrics | BIPA (Illinois) is brutal; explicit written consent |
| Location | High-resolution location is sensitive even when the user is logged in; aggregate or coarsen |
| Government IDs | Encrypted-at-rest at the application layer; access audited; deletion on schedule |
War story
A "remember the user's last 100 search queries" feature seemed innocuous. Two years later, a subpoena landed and the company had to produce two years of search history per user — including queries entered by mistake, by family members on shared devices, by minors. They hadn't documented retention, hadn't built deletion, hadn't asked whether they needed the history at all. The fix retroactively was painful: 30-day retention, app-level encryption, per-user delete on demand. Should have been: don't store more than 7 days unless the user opts in.
Quick checklist
- Only fields the product needs are collected
- All transit encrypted (HTTPS, HSTS); internal hops too
- High-sensitivity fields encrypted at app level with a managed KMS
- Card data handled via tokenization (Stripe Elements / Checkout)
- Audit log for sensitive-data access
- Real deletion path (DB + indexes + caches + sub-processors), tested end-to-end
- Data export is structured and complete
- Logger redaction config blocks passwords, tokens, full PII
- Region-pinned for users with residency requirements
- DPA in place with sub-processors who touch user data
- Backup retention documented; deletion ages backups out predictably
- Privacy policy lists every sub-processor
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

