Gustavia

Security

A plain-English explainer of how we keep your data safe.

Per-user encryption

Every OAuth token, 2FA secret, and backup code we hold is encrypted with a key that is different for every customer. Even our database administrators cannot read your tokens — they would need both the database backup AND our master key, and the master key only ever lives in process memory and a sealed password manager.

master_key  ──HKDF-SHA256──>  your_user_key
                 ▲
            (master + your user id)

your_user_key ──AES-256-GCM──>  ciphertext stored in DB
              + random 12-byte IV
              + auth tag (verified on every read)

Algorithm

Tenant isolation

Every API endpoint scopes every query by your user id. We never trust route parameters as authorisation. We have automated tests that prove User B cannot read, save, dismiss, or write-to-calendar against User A's data, and that the per-user encryption keys are cryptographically bound to the user id (so a row stolen from User A can never be decrypted by User B's key).

What we log, what we don't

Server access logs include path, status code, and your user id. We do not log message bodies, recipient identities, OAuth tokens, or passwords. Audit log entries store only the action type, a SHA-256 hash of your IP, and a truncated user-agent. Error reporting (Sentry) auto-redacts request bodies, query strings, Authorization/Cookie headers, and your email before any event leaves our servers.

Hardening checklist

Responsible disclosure

Found a bug? Email [email protected] with proof-of-concept. We respond within 48 hours, fix confirmed issues within 30 days for High/Critical, and credit you publicly if you want. Please give us a reasonable window before public disclosure (90 days for most, 7 days for actively-exploited issues).