Security
Security is built into Leadia at every layer. Here is what we do and how to reach us.
Report a Vulnerability
Do not report security vulnerabilities through public GitHub issues.
Email: security@getleadia.com
Include in your report:
- Description of the vulnerability
- Steps to reproduce (proof of concept if possible)
- Impact assessment (what data or functionality is affected)
- Your name or handle for attribution (optional)
We will acknowledge receipt within 48 hours, provide an initial assessment within 5 business days, and credit you in our release notes once patched (if you want attribution). We do not currently offer a paid bug bounty.
Compliance
| Standard | Status | Notes |
|---|---|---|
| SOC 2 Type II | In Progress | Controls registry active. Audit in progress. |
| HIPAA | Implemented | PHI encryption, BAA gating, PHI access log, Azure OpenAI BAA path. |
| TCPA | Implemented | Consent versioning, opt-out tracking, quiet hours enforcement. |
| CAN-SPAM | Implemented | Unsubscribe tracking, bounce handling. |
| GDPR | Implemented | Right to erasure, data portability endpoints. |
| CCPA | Implemented | Same endpoints as GDPR. We do not sell data. |
Data Isolation
Every table includes a non-nullable tenant_id column.
- Supabase Row Level Security (RLS) enforced on all tenant-scoped tables. No exceptions.
- Per-tenant key derivation for PII encryption using HMAC-SHA256 from the root key.
- Cross-tenant queries are cryptographically blocked by authenticated encryption (AES-256-GCM auth tag).
Encryption
- PII (email, phone): AES-256-GCM with a per-tenant derived key and random IV per operation.
- PHI (HIPAA, medspa vertical only): AES-256-GCM with a separate master key. BAA required.
- Keys are never stored in the database. They live in environment variables only.
- Transport: TLS 1.2+ enforced on all connections. HSTS with 2-year max-age and preload.
Authentication
- JWT-based sessions via Supabase Auth.
- Session cookies are httpOnly, secure, and SameSite=Lax.
- API keys are stored as HMAC-SHA256 hashes, never in plaintext.
- Plan entitlement cookies are HMAC-signed to prevent feature gate bypass.
- Internal service routes use a shared secret (TRIGGER_INTERNAL_SECRET).
Rate Limiting
Upstash Redis sliding-window rate limiter is active on all API routes.
- AI routes: 20 requests per minute per IP
- Messaging routes: 30 requests per minute per IP
- Billing routes: 10 requests per minute per IP
- Auth routes: 10 requests per minute per IP
Audit Logging
- Immutable audit_events table captures all user and AI actions.
- PHI access is separately logged in phi_access_log (HIPAA requirement).
- GDPR export requests are logged. Deletion requests trigger a 30-day SLA tracking record.
Webhook Security
- Twilio: X-Twilio-Signature HMAC-SHA1 verification on all inbound webhooks.
- Stripe: Stripe-Signature HMAC-SHA256 verification via stripe.webhooks.constructEvent().
- SendGrid: ECDSA signature verification on inbound event webhooks.
Infrastructure Providers
| Service | Provider | Certifications |
|---|---|---|
| Hosting | Vercel | SOC 2 Type II, ISO 27001 |
| Database | Supabase | SOC 2 Type II |
| Rate Limiting | Upstash | SOC 2 Type II |
| Error Tracking | Sentry | ISO 27001 |
| Resend | SOC 2 Type II | |
| SMS | Twilio | ISO 27001, HIPAA BAA available |
| AI (PHI path) | Azure OpenAI | HIPAA BAA available — required before medspa PHI use |
BAAs with subprocessors (Supabase, Vercel, OpenAI, Twilio) are required before any medspa PHI tenant is onboarded. See our go-live checklist.
Dependency Security
We use GitHub Dependabot for automated weekly dependency vulnerability scanning. Dependabot PRs are reviewed and merged within 5 business days. Our CI pipeline also runs npm audit on every push to main, failing on high or critical vulnerabilities.
Known Limitations
- Rate limiting fails open if Upstash Redis is unavailable. We accept this tradeoff to avoid blocking legitimate traffic during infrastructure outages.
- Audit event rows are not cryptographically signed. Tampering by a service-role key holder cannot be detected at the database layer.
- AI run inputs are logged for debugging. Full PII scrubbing before storage is planned for a future release.