Security
Last updated: 2026-05-24
How we protect your account, your data, and your customers' email addresses.
TL;DR
- Passwords hashed with bcrypt. API keys stored as SHA-256 hashes — we never see plaintext after the moment of issue.
- Optional TOTP-based 2FA on every account. Session revocation across all devices in one click.
- Email addresses you verify are stored as SHA-256 hashes only — plaintext lives in memory for the duration of the request, then is gone.
- Webhook URLs are validated against SSRF (loopback / private / metadata IPs blocked).
- Webhook payloads signed with HMAC-SHA256. Paddle webhooks signature-verified.
- Login brute-force gated atomically per IP. Per-key rate limits.
- Full audit trail for every admin action.
Authentication
- Passwords: bcrypt with cost factor 10. We enforce 8+ character minimum.
- API keys: 256-bit random, prefix
tm_. Stored as SHA-256 hash — we cannot recover them, only revoke and reissue. - 2FA: TOTP via any RFC-6238 authenticator (Authy, 1Password, Google Authenticator). Required code on every sign-in once enabled.
- Sessions: JWT with embedded token-version. "Sign out everywhere" bumps the version and invalidates every outstanding session instantly.
- Constant-time login: bcrypt runs even for unknown email addresses so attackers can't enumerate accounts by timing.
- Brute-force gate: 5 failed attempts per IP per 15 min returns
429withRetry-After.
Data at rest & in transit
- In transit: TLS 1.2+ on every public endpoint with HSTS (2-year max-age, preload).
- At rest: Postgres database encrypted by the hosting provider.
- Verifications: SHA-256 hash + domain + verdict. The plaintext email is not written to the database, log files, or cache.
- Password reset tokens: stored as SHA-256 hash; a DB-snapshot leak can't be used to reset accounts.
- Backups: daily encrypted snapshots, 30-day retention.
Infrastructure
- Stateless Go API behind a reverse proxy with TLS termination.
- NATS for async job queueing; not exposed to the public internet.
- Redis for caches and rate-limit counters; private network only.
- Postgres for durable state; private network only, no public port.
- Webhook delivery refuses HTTP redirects and re-validates the target host before each delivery (defends against DNS rebinding).
- Content-Security-Policy, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin, Permissions-Policy locked down.
Operational security
- All admin actions are logged to an immutable audit trail (actor, action, target, timestamp).
- Production access uses unique per-engineer credentials, MFA required.
- SSH keys, not passwords. No shared accounts.
- Dependency updates via Dependabot, security advisories reviewed weekly.
- Worker logs scrub email addresses to
f***@domainform — no full PII at INFO level.
Incident response
We'll notify affected customers within 72 hours of becoming aware of a personal data breach, with the facts available and our mitigation. See the DPA for the contractual commitment.
Responsible disclosure
Found a vulnerability? Please don't post it publicly. Email security@trumailo.com with a description and reproduction steps. We'll acknowledge within 48 hours and credit you (if you want) once a fix is shipped. We don't prosecute good-faith security research that follows this process.
Compliance roadmap
- GDPR & UK GDPR: covered by our DPA and privacy policy.
- CCPA: covered by our privacy policy.
- SOC 2 Type II: on the roadmap, targeted for the post-beta milestone.
- ISO 27001: on the roadmap, after SOC 2.
Questions about this policy? Email legal@trumailo.com or use the contact form.