Security controls
What we have in place today, what's in flight, and what's on the roadmap. Each item describes a real control verifiable against our codebase or infrastructure.
Authentication & Access
Every super-admin route is gated by a server-side AAL2 check. Super admins cannot reach administrative tooling without passing a TOTP challenge.
Any user can enroll a time-based one-time password authenticator from their account settings.
Access tokens expire every hour. Refresh-token rotation is enabled with a 10-second reuse interval — a stolen refresh token self-invalidates almost immediately on the next legitimate use.
Three administrative tiers — professional, location admin, company admin — plus a super-admin role for platform operators. Every database query enforces the tier through Row Level Security and column-level grants.
Minimum 10 characters with mixed case and digits, enforced at sign-up and password reset. Passwords are stored as bcrypt hashes by Supabase Auth.
Sign-in, sign-out, password-reset request, password-reset completion, MFA challenges, and super-admin impersonation all write structured rows to a tamper-resistant audit log.
Data Protection
TLS 1.2+ enforced on every public endpoint. HTTP is redirected to HTTPS at the edge.
All Postgres data and uploaded files are encrypted at rest via AWS-managed keys (AES-256) through Supabase's managed infrastructure.
75 tables enforce per-tenant access policies in the database itself, not just at the application layer. A bug in application code cannot expose data outside its scope.
Sensitive columns (email addresses, API keys, billing identifiers, payment tokens) are revoked from the anonymous role at the database level. Even a misconfigured public query cannot return them.
Public review-display endpoints return only first name, last name, and review content. Reviewer email and verification hashes are never serialized to the client.
Audit & Monitoring
Authentication events, billing changes, super-admin impersonation, and customer-data exports all record to an audit log with actor, timestamp, IP address, and user-agent.
Every Stripe webhook event we act on writes an audit row — subscription created, updated, canceled, payment past due — with the originating Stripe event ID for cross-reference.
Every CSV or PDF export from the reporting module is logged with row count, source, columns selected, and the exporting user.
Super admins may impersonate users for support purposes. Each impersonation start and end records the actor, target user, and reason.
Application Security
Stripe webhooks are verified with HMAC-SHA256 using a constant-time comparison. Inbound SMS (Telnyx) and email-event (Resend) webhooks verify signed payloads before processing.
Webhook event IDs are recorded before any side effect. Replays are rejected, eliminating an entire class of duplicate-charge and duplicate-state bugs.
Every API route validates inbound JSON with a Zod schema. Mismatched payloads are rejected with a 400 before they reach business logic.
All database access goes through parameterised PostgREST queries. There is no string-concatenation SQL in application code.
CSP rolls out in report-only mode first so we can observe and tighten before enforcement. Target enforcement window: Q3 2026.
Network & Rate Limiting
Public-facing endpoints are rate-limited per-IP through Upstash Redis. Authentication endpoints have a stricter window to deter credential-stuffing.
Vercel's edge network absorbs volumetric attacks before traffic reaches application code.
Vulnerability Management
Dependabot opens pull requests for security and minor updates weekly across npm, GitHub Actions, and Python dependencies.
Researchers can report security issues to security@eendorsements.com. We acknowledge within five business days and follow a 90-day coordinated-disclosure window.
TypeScript with strict mode is enforced project-wide; a non-typing change cannot land without passing the typecheck.
External penetration test scheduled within six months of GA. Summary report will be available to enterprise customers under NDA.
Backups & Recovery
Supabase performs continuous WAL backups with point-in-time recovery within the retention window of our database tier.
Restore runbook with target RTO of 4 hours and RPO of 24 hours is in draft. Quarterly restore drills will be added once finalized.