18Core
Compliance & GDPR
Compliance & GDPR — Instruction 18
Coverage
GDPR/RGPD, HIPAA, PCI-DSS, SOC2 — PII detection and compliance CWE-200, CWE-312, ASVS V8
PII Detection
1. PII Patterns in Code
Scan for these patterns being passed to:
- Logs, API responses, localStorage, cookies
// PII fields to track:
user.email // GDPR: requires consent, cannot be logged
user.phone // GDPR: sensitive
user.firstName // GDPR: personal data
user.lastName // GDPR: personal data
user.birthDate // GDPR: sensitive
user.address // GDPR: sensitive
user.ip // GDPR: personal data
user.password // CRITICAL: never log, never return
user.ssn // HIPAA/US: critical
user.creditCard // PCI-DSS: never store unencrypted
user.cvv // PCI-DSS: NEVER store (even encrypted)
user.bankAccount // Sensitive: encrypt at rest
user.passport // GDPR: sensitive
user.healthData // HIPAA: critical
2. PII Not in Logs
// 🔴 GDPR violation — PII in server logs
logger.info('User login', { email: user.email, ip: req.ip })
logger.error('Failed payment', { creditCard: card.number })
// 🟢 Log minimal, non-identifying data
logger.info('User login', { userId: user.id, timestamp: Date.now() })
logger.error('Failed payment', { userId: user.id, last4: card.last4 })
// 🟢 If logging IP (for security) — document legal basis
// IP is personal data under GDPR
3. PII Not in API Responses
// 🔴 Password hash in API response
res.json({ user }) // user object contains passwordHash!
// 🟢 Exclude sensitive fields
const { passwordHash, ...safeUser } = user
res.json({ user: safeUser })
// 🟢 Or use field projection
const user = await User.findById(id).select('-passwordHash -internalNotes')
4. PII Not in URLs
// 🔴 GDPR: URLs logged by servers, proxies, browsers
GET /users/search?email=john@example.com // email in server logs
GET /profile?ssn=123456789 // SSN in URL!
// 🟢 PII via POST body or header only
POST /users/search
Body: { "email": "john@example.com" }
GDPR Checks
5. Data Minimization
// 🔴 Collecting more data than needed
await User.create({
email: req.body.email,
phone: req.body.phone, // needed?
birthDate: req.body.birthDate, // needed?
gender: req.body.gender, // needed?
address: req.body.address // needed?
})
// 🟢 Collect only what's strictly necessary
// Document why each field is collected (in privacy policy)
6. Data Retention
// 🔴 Data kept forever
// 🟢 Define and enforce retention periods
// Example: inactive accounts → anonymize after 2 years
// Delete: logs after 90 days, sessions after 30 days
// Check if there are scheduled jobs for data cleanup
// Check if there's a privacy policy with retention periods
7. Right to Erasure
// 🔴 No delete functionality — GDPR violation
// 🟢 Implement user data deletion
app.delete('/api/users/me', auth, async (req, res) => {
// Delete or anonymize user data
await User.findByIdAndUpdate(req.user.id, {
email: `deleted_${Date.now()}@deleted.com`,
name: 'Deleted User',
// ... anonymize all PII
deletedAt: new Date()
})
// Delete: sessions, orders (or anonymize), reviews, logs
res.json({ message: 'Account deleted' })
})
8. Consent Management
// 🔴 Cookies set without consent
document.cookie = '_ga=...' // analytics without consent
// 🟢 Implement consent before any non-essential cookies
// Check: is there a cookie consent banner?
// Check: are analytics/marketing cookies set only after consent?
// Check: is consent stored and respected?
9. Privacy Policy
- Check if
privacy-policyroute/page exists - Check if terms-of-service exists
- Flag if missing (info)
HIPAA (if healthcare data detected)
10. HIPAA-Specific Requirements
Detected when: medical, health, patient, diagnosis, prescription in codebase
// HIPAA Technical Safeguards:
// ✅ Encryption in transit (TLS 1.2+) — already checked
// ✅ Encryption at rest for PHI
// ✅ Access controls (auth) — already checked
// ✅ Audit logs for all PHI access
// ✅ Automatic logoff (session timeout)
// ✅ Unique user identification
// ✅ Emergency access procedure
// Check audit logging for PHI access:
app.use('/api/patients', auth, (req, res, next) => {
hipaaLogger.info({
userId: req.user.id,
action: req.method,
resource: 'patient_data',
patientId: req.params.id,
timestamp: new Date().toISOString()
})
next()
})
PCI-DSS (if payment processing detected)
11. Card Data Rules
Detected when: stripe, payment, card, checkout, billing in codebase
// 🔴 CRITICAL PCI violations:
// Storing CVV (never, even encrypted)
// Storing full PAN (card number) without tokenization
// Logging card data
// 🟢 PCI-Compliant approach:
// Use Stripe/Braintree/Square tokenization — never handle raw card data
// Stripe.js collects card data directly in browser → Stripe servers
// You only receive a token
// Check:
// - Payment library used (Stripe, etc.)
// - No raw card numbers in your code/database
// - No CVV stored anywhere
// - HTTPS everywhere on payment pages (already checked)
Data at Rest Encryption
12. Sensitive Fields Encrypted in Database
// Fields that MUST be encrypted at rest:
// - creditCard (if stored, though you shouldn't)
// - ssn, passport, government ID
// - health/medical data
// - bank account numbers
// Application-level encryption (works with any DB)
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto'
const ENCRYPTION_KEY = Buffer.from(process.env.ENCRYPTION_KEY, 'hex') // 32 bytes
function encrypt(text) {
const iv = randomBytes(16)
const cipher = createCipheriv('aes-256-gcm', ENCRYPTION_KEY, iv)
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()])
const tag = cipher.getAuthTag()
return iv.toString('hex') + ':' + tag.toString('hex') + ':' + encrypted.toString('hex')
}
function decrypt(data) {
const [ivHex, tagHex, encryptedHex] = data.split(':')
const iv = Buffer.from(ivHex, 'hex')
const tag = Buffer.from(tagHex, 'hex')
const encrypted = Buffer.from(encryptedHex, 'hex')
const decipher = createDecipheriv('aes-256-gcm', ENCRYPTION_KEY, iv)
decipher.setAuthTag(tag)
return decipher.update(encrypted) + decipher.final('utf8')
}