Security model
Protect the stored record. Explain the plaintext boundary.
Compromised reduces exposure in storage and responses, but it is not zero-knowledge or end-to-end encrypted. The server must see the submitted value to validate it and send it to the configured breach provider.
Data path
Four controls around sensitive search records.
Authenticated encryption
New search values and resolved client IPs are sealed with AES-256-GCM. Additional authenticated data binds ciphertext to its collection, document, field, type where applicable, and encryption-key version.
Purpose-separated blind indexes
HMAC indexes are calculated over normalized values for exact lookup and network-scope controls. Search-value, IP, and IP-scope purposes are separate, and key and normalization versions travel with the record.
Explicit reveal boundary
History listings do not decrypt values. Owner reveal requires an active capability, an owner-scoped database lookup, an identified actor, and an audit reason before server-side decryption.
Bounded browser data
Server DTOs omit fields that the current entitlement does not allow. API responses use private no-store caching, and search values are submitted in JSON bodies rather than URLs.
Defence in depth
Policy is enforced before data reaches the browser.
- Identity
- Auth.js JWT sessions identify a subject, but protected Node routes resolve that subject against MongoDB before authorizing data. Google profiles require verified email, and matching email alone cannot silently link an OAuth account.
- Abuse controls
- Anonymous searches and contact submissions verify distinct Turnstile actions, require a rate-limitable network scope, and consume atomic MongoDB rate-limit buckets derived from HMAC identifiers. Magic-link email dispatch is rate-limited by email and network scope.
- Provider boundary
- The upstream adapter validates configuration, uses HTTPS, declines redirects, enforces a timeout and response-size bound, then discards unknown fields and arbitrary prose before constructing a normalized result.
- Billing
- Checkout and portal redirects are restricted to an expected set of HTTPS hosts. Webhooks require signature verification over a bounded raw body, are recorded idempotently so a replayed or retried event cannot grant access twice, are checked against the account they claim to belong to, and are applied in order so a late-arriving stale event cannot undo a newer one. Card details are handled entirely by the payment provider and never reach this application.
- Logs and analytics
- The logger redacts sensitive keys, email and IP patterns, binary values, long strings, and deep objects. Analytics is off unless an administrator turns it on, and every event is validated against a named schema whose properties are booleans and closed enums — there is no free-form field anywhere in the contract, so a searched value has nowhere to go. An event that fails validation is dropped rather than sent.
- Browser policy
- Global headers deny framing and MIME sniffing, restrict permissions, mark the origin for HSTS, and apply a CSP limited to the application plus Cloudflare Turnstile. Next.js currently requires inline bootstrap and style allowances, so the CSP is not nonce-only.
Boundaries that remain
Application encryption protects stored fields from a database-only exposure; it does not protect against compromise of the running server and its keys. Blind indexes intentionally disclose when normalized inputs are equal to a party able to query those indexes.
The exact query leaves the encryption boundary while the server calls the provider. Provider coverage and accuracy are outside this application's control. Normalization reduces the returned surface, but it does not verify every upstream fact.
The repository contains staged migration tooling for inherited plaintext records and gates normalized snapshot persistence on confirmed MongoDB transaction support. Source inspection cannot prove that a production migration ran, keys were rotated, the transaction flag was enabled, or the documented Cloudflare firewall and authenticated-origin controls were deployed.
Report a security concern without sending the secret.
Include reproducible steps and impact, but remove search values, credentials, tokens, private keys, and personal data from the first message.