Skip to content

feat: add field-level encryption for PII#102

Merged
suesuee merged 3 commits intodevelopfrom
feat/field-encryption
Mar 27, 2026
Merged

feat: add field-level encryption for PII#102
suesuee merged 3 commits intodevelopfrom
feat/field-encryption

Conversation

@kevinrutledge
Copy link
Copy Markdown
Collaborator

@kevinrutledge kevinrutledge commented Mar 27, 2026

Developer

Kevin Rutledge

What changed?

Added AES-256-GCM field-level encryption for PII stored in the Referral, EmailSuppression, and SmsConsent tables. Encrypted fields are stored as base64url ciphertext. Lookup tables (EmailSuppression, SmsConsent) use HMAC-SHA256 blind indexes for exact-match queries without decrypting. Also ran npm audit fix to resolve 18 of 19 dependency vulnerabilities.

New files:

  • src/lib/encryption.ts - encrypt(), decrypt(), blindIndex() using Node.js crypto
  • test/lib/encryption.test.ts - 13 tests for round-trip, tamper detection, blind index determinism
  • test/mocks/encryption.ts - shared passthrough mock for service/action/API tests
  • scripts/migrate-encrypt-pii.ts - one-time data migration script for existing rows

Modified:

  • prisma/schema.prisma - widened PII columns to VarChar(512), added emailHash/phoneHash columns, updated indexes
  • src/services/referral.ts - encrypt on write, decrypt on read for 4 PII fields
  • src/services/email-suppression.ts - blind index lookups, encrypted email storage
  • src/env.ts - added FIELD_ENCRYPTION_KEY and BLIND_INDEX_KEY env vars

How to test

  1. Add encryption keys to .env.local: openssl rand -hex 32 for each of FIELD_ENCRYPTION_KEY and BLIND_INDEX_KEY
  2. Run npm test - 237 tests pass (14 new encryption tests)
  3. Run npm run build - build succeeds
  4. Run npx tsc --noEmit - zero type errors
  5. Start dev server, submit a referral form, inspect the referral table - PII fields should contain base64url ciphertext, not plaintext
  6. Run npm audit - down to 1 low-severity vulnerability (nodemailer, requires breaking major version)

Checklist

@kevinrutledge kevinrutledge requested a review from suesuee March 27, 2026 21:35
@kevinrutledge kevinrutledge self-assigned this Mar 27, 2026
@suesuee suesuee merged commit a44211b into develop Mar 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants