PII encrypted at the field level
Sensitive identifiers (full name, address, SSN-last-4, account numbers, dispute narratives) are encrypted with AES-256-GCM before they touch the database. Encryption keys are stored separately from data, rotated on a documented schedule, and never logged.
Active key version: PII_KEY_V1 · pseudonym secret separate
TLS 1.3 in transit
All client-to-server, server-to-database, and webhook traffic runs over TLS 1.3 with modern cipher suites. HSTS preload prevents protocol downgrade. We do not log decrypted PII at any layer.
Enforced via HSTS + Vercel edge
Webhook signatures HMAC-verified
Every Stripe and Denefits webhook is verified against its HMAC signature before processing. Replay-protected via timestamp tolerance. Failed verifications are logged and rejected at HTTP 400 — never silently accepted.
Stripe SDK constructEvent · Denefits SHA-256 HMAC
Row-level security on every table
Supabase RLS policies enforce that you can only read and write your own cases, letters, and documents. Policies are defined in migrations (version-controlled) and audited for every new table.
Postgres RLS · enforced at the database, not the app