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

Multi-factor authentication enforced for super admins
Implemented

Every super-admin route is gated by a server-side AAL2 check. Super admins cannot reach administrative tooling without passing a TOTP challenge.

TOTP enrollment available to all users
Implemented

Any user can enroll a time-based one-time password authenticator from their account settings.

Session timeouts and refresh-token rotation
Implemented

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.

Role-based access control
Implemented

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.

Strong password policy
Implemented

Minimum 10 characters with mixed case and digits, enforced at sign-up and password reset. Passwords are stored as bcrypt hashes by Supabase Auth.

Audit logging on authentication events
Implemented

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

Encryption in transit
Implemented

TLS 1.2+ enforced on every public endpoint. HTTP is redirected to HTTPS at the edge.

Encryption at rest
Implemented

All Postgres data and uploaded files are encrypted at rest via AWS-managed keys (AES-256) through Supabase's managed infrastructure.

Row Level Security on every customer-data table
Implemented

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.

Column-level grants block PII from anonymous access
Implemented

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.

Sensitive columns excluded from public APIs
Implemented

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

Append-only audit log
Implemented

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.

Subscription lifecycle audit
Implemented

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.

Data export audit
Implemented

Every CSV or PDF export from the reporting module is logged with row count, source, columns selected, and the exporting user.

Super-admin impersonation tracking
Implemented

Super admins may impersonate users for support purposes. Each impersonation start and end records the actor, target user, and reason.

Application Security

Webhook signature verification
Implemented

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.

Idempotent webhook processing
Implemented

Webhook event IDs are recorded before any side effect. Replays are rejected, eliminating an entire class of duplicate-charge and duplicate-state bugs.

Input validation
Implemented

Every API route validates inbound JSON with a Zod schema. Mismatched payloads are rejected with a 400 before they reach business logic.

SQL injection resistance
Implemented

All database access goes through parameterised PostgREST queries. There is no string-concatenation SQL in application code.

Content Security Policy
In progress

CSP rolls out in report-only mode first so we can observe and tighten before enforcement. Target enforcement window: Q3 2026.

Network & Rate Limiting

Distributed rate limiting on public endpoints
Implemented

Public-facing endpoints are rate-limited per-IP through Upstash Redis. Authentication endpoints have a stricter window to deter credential-stuffing.

Edge-network DDoS mitigation
Implemented

Vercel's edge network absorbs volumetric attacks before traffic reaches application code.

Vulnerability Management

Automated dependency updates
Implemented

Dependabot opens pull requests for security and minor updates weekly across npm, GitHub Actions, and Python dependencies.

Coordinated vulnerability disclosure
Implemented

Researchers can report security issues to security@eendorsements.com. We acknowledge within five business days and follow a 90-day coordinated-disclosure window.

Type-checked codebase
Implemented

TypeScript with strict mode is enforced project-wide; a non-typing change cannot land without passing the typecheck.

Production penetration testing
Roadmap

External penetration test scheduled within six months of GA. Summary report will be available to enterprise customers under NDA.

Backups & Recovery

Daily automated backups with point-in-time recovery
Implemented

Supabase performs continuous WAL backups with point-in-time recovery within the retention window of our database tier.

Documented recovery procedure
In progress

Restore runbook with target RTO of 4 hours and RPO of 24 hours is in draft. Quarterly restore drills will be added once finalized.