# Security and privacy ## Protected values Email addresses, phone numbers, FCM installation ids and legacy tokens, APNs device tokens, Web Push endpoints and keys, VAPID private keys, provider credentials, callback signing secrets, template variables, rendered bodies, attachment references and unsubscribe tokens. ## At rest Contact points are encrypted with AES-256-GCM. Equality lookup uses a separate HMAC-SHA-256 fingerprint. Two keys, not one, because the requirements are opposite: the ciphertext must be non-deterministic so two records of the same address are not visibly identical, while equality lookup must be deterministic. The fingerprint is keyed rather than a plain digest because phone numbers and email addresses come from a small, enumerable space — an unkeyed hash of a phone number is recoverable in seconds. The contact point kind is bound into the GCM associated data, so a ciphertext cannot be moved between contact kinds without failing the authentication tag. An unknown key id is refused rather than silently falling back to the current key: a silent fallback would turn every historical row into a tag failure at read time. ## Never logged, never a metric tag Addresses, tokens, Web Push endpoints and keys, message bodies, template variables, provider credentials, unsubscribe tokens, attachment URLs, raw callback payloads and raw provider request ids. Two mechanisms enforce this rather than convention: - `CardinalityGuard` validates every metric tag against a closed allowlist. - `SafeDiagnosticContext` rejects any structured-diagnostic field outside its allowlist. An allowlist rather than a denylist, because the failure mode of a denylist is that the one field nobody thought of is the one that leaks. Every contact point value type overrides `toString()` to print `[redacted]`. That covers the case a central redactor cannot: a value interpolated into a log line by accident. ## Web Push endpoints RFC 8030 defines the push URI as a capability URL — knowing it is sufficient to push to the subscriber. It is handled as a secret, not as a URL. ## Callbacks TLS, provider signature verification over the exact received bytes and external URL, replay defence where a timestamp or nonce is available, body-size and content-type limits, profile binding, rate limiting, idempotent ingestion and a security audit trail for rejections. ## Tenant isolation Every store port carries the tenant boundary in its signature. Administrative operations require an explicit tenant or a global authority.