FixVibe

// docs / security guides / pre-launch SaaS

Checklist sécurité pré-lancement SaaS : 35+ items

You are days from launching a SaaS product built with Cursor, Claude Code, Lovable, or Bolt. This checklist is a go/no-go audit covering the security surfaces that AI tools consistently miss and that founders shipping fast need to address before taking customer money. Eight sections, 35+ items, each resolvable in 30-90 minutes. Print it, cross it off, deploy with confidence.

Each item below is essential. Green means shipped and verified; red means unresolved and blocking launch. For a longer walkthrough of each category with code snippets and real failure patterns, see How to secure an app built with AI coding tools and The vibe coding security checklist.

Customer data isolation

In a multi-tenant SaaS, your first security boundary is data isolation. Every customer's data must be unreachable to every other customer, enforced at the database layer, not the application layer.

  1. Enable Row-Level Security (RLS) on every Supabase table with ALTER TABLE public.table_name ENABLE ROW LEVEL SECURITY; ALTER TABLE public.table_name FORCE ROW LEVEL SECURITY;. FORCE prevents the table owner from bypassing it.
  2. For each RLS policy, verify the predicate scopes to the authenticated user or organization. Example: CREATE POLICY "users_see_own" ON public.items FOR SELECT USING (auth.uid() = user_id);. Test with a second user account to confirm data stays isolated.
  3. If using Firebase / Firestore, rules must match your tenant model. Do not use allow read, write: if true; or time-bounded test rules. Use allow read, write: if request.auth.uid == resource.data.owner_uid; or equivalent org-scoped matching.
  4. Use signed URLs or short-lived tokens for file access, never public buckets. Supabase Storage: set ENABLE ROW LEVEL SECURITY on the objects table and author policies that scope file access to the authenticated user. Test downloads as different users.
  5. On your API layer, every request must include auth.uid() or org-id context. Every database query must filter by that context. Example: no SELECT * FROM items WHERE id = $1; always SELECT * FROM items WHERE id = $1 AND user_id = auth.uid().

Billing and payment

Stripe integration is where customer trust meets financial safety. Misconfiguration here means stolen payments, refund loops, or missing revenue.

  1. Use live Stripe keys in production. Test with a separate test-mode key on staging. Never flip the switch from test to live without a final live-mode scan.
  2. Verify webhook signature on every inbound event: const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);. Throw if the signature fails. Store the webhook secret in an environment variable only, never in code.
  3. Implement idempotency on webhook handlers using a database table keyed by event.id. If the same webhook arrives twice (it will), the second run is a no-op. Write the idempotency row in the same transaction as the state change.
  4. On customer.subscription.updated and customer.subscription.deleted, immediately revoke access. Do not wait for a cron. Test by canceling a subscription in Stripe Dashboard and verifying the user is locked out within 5 seconds.
  5. Store only the Stripe customer ID and subscription ID in your database, never the full card or API key. Retrieve live subscription state from Stripe on every auth boundary (page load, API call, cron check). Do not cache subscription status for >1 minute.

Authentication and sessions

Auth is the second-order attacker target in SaaS. A user account is a vector to data and payment methods.

  1. Use supabase.auth.getUser() on every protected route, never getSession(). getSession() reads an unverified cookie; getUser() validates the JWT server-side. In Next.js: const { data: { user } } = await supabase.auth.getUser(); before serving protected content.
  2. Set SameSite=Lax on auth cookies (Supabase Auth does this by default). Verify in DevTools → Application → Cookies. If you see SameSite=None, add sameSite: 'Lax' to your session config.
  3. Enable MFA on your own admin account. For user-facing MFA, test it end-to-end before launch: sign up, enroll a TOTP device, sign out, sign back in with the TOTP token, verify it works.
  4. Magic-link tokens must expire within 15 minutes. Password-reset tokens must expire within 1 hour. Session tokens (JWTs) can live longer (24h-7d) but must be validated on every use. Check your auth provider's defaults.
  5. Test sign-out completeness: after a user clicks sign-out, the browser deletes the auth session, server revokes any tokens, and the user cannot access protected pages. In Supabase: call await supabase.auth.signOut() and verify the JWT is no longer valid on the next request.

PII and compliance

If you collect email, name, payment info, or any PII, you have legal obligations: data minimization, secure storage, deletion on demand, and DPA readiness.

  1. Write and publish a privacy policy (not optional, even for indie SaaS). State what data you collect, why, how long you keep it, and user rights (access, correction, deletion). Use a template from Termly or similar but customize it.
  2. Implement a delete-account API endpoint that purges PII from the database. Test it: create an account, add data, delete the account, verify the data is gone (use direct database inspection).
  3. For GDPR / CCPA compliance, respond to data-subject requests (access / correction / deletion) within 30 days. Document your process. If your app is EU-based or serves EU users, a Data Processing Addendum (DPA) with Stripe, Supabase, and any processor is required.
  4. Encrypt sensitive fields at rest (passwords are hashed by your auth provider; but credit-card tokenization, API keys, secrets should use pgcrypto or an external vault). Never store plaintext credit-card numbers (use Stripe tokenization instead).

Operational readiness

Security is continuous. Incident response, monitoring, and runbooks start before day one.

  1. Set up a status page (Statuspage.io, Uptime Robot, or a simple index.html). Customers need to know if you're having an outage. Update it on every incident.
  2. Have an on-call rotation documented and tested. Who wakes up on a 2am alert? Who has deploy keys? Who can revoke a compromised token? Document it and run a fire-drill before launch.
  3. Write a security incident response runbook: what to do if a customer reports a breach, if you lose a key, if a service goes down. Distribute it to your team. Test one scenario (e.g., simulate a key leak) to verify the plan works.
  4. Backup and restore procedures must be tested, not theoretical. Can you restore from backups? Time it. Supabase: enable automated backups (7-day retention on free, 30-day on paid). Test a restore to a separate project quarterly.
  5. Enable audit logging for privileged operations: Stripe dashboard logins, Supabase admin API calls, database schema changes, payment reconciliation. Tools: CloudTrail (AWS), Supabase audit logs, PostgreSQL pgaudit extension.

External attack surface

Your API boundary is under constant attacker scan. Lock it down before malicious traffic hits.

  1. Rate-limit every public endpoint. Example: 100 requests per minute per IP on sign-up, 10 per minute on password reset. Use Vercel KV, Redis, or similar. Fail with 429 (Too Many Requests).
  2. Add CAPTCHA (hCaptcha or reCAPTCHA) to sign-up and password-reset endpoints to defeat bots. Verify the token server-side before accepting the request.
  3. Use a WAF (Web Application Firewall) if available: Cloudflare, Vercel Web Application Firewall, or AWS WAF. Block known-malicious IPs and patterns automatically.
  4. Scan for open API endpoints. Run a passive FixVibe scan against your production domain monthly. Review findings for exposed debug routes, GraphQL introspection, API key leakage, or configuration exposure.
  5. Rotate credentials (API keys, OAuth tokens, database passwords) quarterly. Document the rotation procedure and automate it where possible.

Observability and logging

When things go wrong, logs are your forensic record. Set them up from day one.

  1. Centralize logs: Supabase Logs, Vercel Logs, application logs, and auth logs to a single dashboard (Datadog, LogRocket, or self-hosted ELK). Searchable, retained for at least 90 days.
  2. Alert on security events: repeated failed logins (possible account takeover), unusual API usage (possible scraping), error spikes (possible attack or legitimate incident). Set thresholds and Slack integrations.
  3. Emit audit logs for every privileged operation: user role changes, new admin account creation, payment method additions, scope changes in API keys. Store these separately from application logs with immutable retention.

Final verification

Before you announce, run a full FixVibe scan and review the findings with a security eye.

  1. Run a FixVibe Pro active scan against your production domain. Configure your domain for active testing (DNS TXT or HTTP file verification). Authorize the scan and review every finding — especially critical and high severity. Fix or accept each one explicitly.
  2. Enable scheduled re-scans: Pro plan → 3h, 6h, 12h, or daily. Unlimited plan → 6h, 12h, daily, every 2 days, or weekly. Pair with active IDOR walking, SQL injection, and reflected XSS checks on your verified domain.
  3. Configure webhooks: connect FixVibe to Slack or email so critical findings trigger alerts in real time. See /docs/webhooks for setup.
  4. Do a final manual code review focusing on the gotchas in /docs/security-guides/ai-generated-code-security-scanner: secrets in bundles, RLS/rules, auth boundaries, CSP, middleware placement. Use the vibe coding security checklist as the review template.

Launch day

You have cleared the checklist. Deploy with confidence. After launch, monitor actively: check FixVibe findings daily for the first week, respond to alerts within 1 hour, and keep the scan schedule running. For a step-by-step hardening guide with code snippets, see How to secure an app built with AI coding tools.

// scanner votre app

Arrêtez de lire. Trouvez les failles dans la vôtre.

Collez une URL — FixVibe exécute tous les contrôles passifs de ce guide plus 200 autres en moins d'une minute. Gratuit, sans installation, sans carte.

  • Plan gratuit — 3 scans / mois, sans carte.
  • Scans passifs contre n'importe quelle URL — pas de vérification de domaine.
  • Optimisé pour Cursor, Claude Code, Lovable, Bolt, v0, Replit.
  • Prompts de correction IA sur chaque résultat — collez-les dans votre IDE.
Checklist sécurité pré-lancement SaaS : 35+ items — Docs · FixVibe