NARA

/security · last updated 29 April 2026

Security that fails
closed, not open.

What we do to protect your data, your sessions, and your bill — and what you can audit yourself from the dashboard. No trust-us marketing: every claim below names the mechanism behind it.

Trust, engineered in.

Encrypted, fail-closed secrets

All Convex data is encrypted at rest by the provider and access is audit-logged. JWT secrets are required in production — no silent dev fallback; the environment fails closed if they're missing.

Isolated object storage

Stored assets — uploads and recordings — live in S3-compatible storage with sha256 fingerprinting and immutable cache headers. Bucket keys are randomised and scoped per (org, user, day, service), so a leaked URL can't be enumerated.

OIDC SSO architecture

One identity across Synapse, Conference, and the dashboard, brokered by the central auth service. Every authenticated route validates the session server-side on every request — role and org claims are never trusted from the client.

Credit-level audit trail

Every credit deduction is a ledger entry and every admin action writes an audit log — who, what, when, source IP, request ID. Your spend and your access history are both inspectable from the dashboard.

Fail-closed by default

If Upstash Redis is unreachable in production, rate-limited requests get 429 instead of a free pass. The per-stream credit gate aborts a chat response the moment credits cross zero mid-generation.

Verified payment webhooks

Gateway events are signature-verified — HMAC with constant-time compare and a 5-minute replay window — then written to an idempotency-keyed ledger so the same event is processed at most once.

Authentication

Every authenticated route validates the session against the auth-service on every request — no client-side trust of role / org claims.

OAuth 2.0 with PKCE S256 only`plain` is rejected.
Refresh tokens rotate on every use; reuse triggers revocation of all sessions for that user.
Token revocation propagates in under 30 seconds via a server-side blocklist (cached for 30s, max 5,000 entries).
2FA via TOTP with backup codes; enforced per-device with 30-day trust windows.

Network + IP

Real client IP is captured from CF-Connecting-IP / X-Real-IP / X-Forwarded-For (in that preference order) on every request.

IP chaining detection flags chains >3 hops, duplicate IPs, and private→public transitions to a security log.
Per-IP signup rate limit (default 5 accounts / 7 days) with auto-block on threshold.
Disposable / temporary email blocklist on signupmailinator, guerrillamail, tempmail, yopmail, 10minutemail, throwaway.email + ~50 more, admin-extensible.

Application

Origin-based CSRF defense on cookie-authenticated POST/PUT/DELETE routes (OWASP "Verifying Origin with Standard Headers" pattern). Bearer-token requests bypass.
Server-side admin role check on every /api/admin/* request — the user_role cookie is never trusted.
Fail-closed rate limits in productionif Upstash Redis is unreachable, requests get 429 instead of pass-through.
Per-stream credit gate during chat streaming aborts the response when credits cross zero mid-generation.

Webhooks

Stripe, PhonePeHMAC verified via the official SDK.
Cashfree, ZohoHMAC-SHA256 verified with constant-time compare and a 5-minute replay window.
Razorpay, PayUprovider-native signature verification.
All payment events are written to an idempotency-keyed ledger; the same gateway event ID is processed at most once.

Data

Stored assets live in S3-compatible object storage with sha256 fingerprinting and immutable cache headers.
Bucket keys are randomised + scoped per (org, user, day, service) so a leaked URL can't be enumerated.
All Convex data is at rest encrypted by the provider; access is audit-logged.
JWT secrets are required in productionno silent dev fallback. The environment fails closed if missing.

Operations

Every admin action writes an audit log (who, what, when, source IP, request ID).
Security events stream to PostHog and to a Convex `securityLogs` table for in-product review.
Session hijack detection compares previous IP+UA to current; mismatches in both at once log a high-severity alert.
Cloudflare Turnstile gates the first generation per session.

Disclosure

Found a vulnerability? Email [email protected]. We respond within 1 business day, triage within 3.

Please give us 90 days to fix before public disclosure. We acknowledge reporters in our changelog with their permission.

We don't run a paid bug bounty (yet) but we do send swag and credits to good reports.

Questions · [email protected]