Launch and other stacks

Pre-launch security checklist for vibe-coded apps

Before you launch an app built with AI tools, check five things in this order: who can read each table (as a visitor and as a second signed-up user), that no secret key is in your code or git history, that roles and admin checks live in the database rather than the browser, that every server function checks who is calling, and that your files and dependencies aren’t exposing anything. This checklist links each item to a self-check and a fix.

TL;DR

  • Data first: test each table with personal data as a logged-out visitor and as a stranger who signed up.
  • Keys: no secret keys in the code, the bundle or git history. Rotate any that ever were.
  • Auth: roles in app_metadata or a roles table, email confirmation on, admin rules enforced by the database.
  • Server code, storage and dependencies: functions verify callers, webhooks verify signatures, private files in private buckets, npm audit clean of serious advisories.

How to use this list

Work top to bottom: the early items expose the most data. Each item says what “done” looks like and links to a guide with the exact commands. It is written for apps built with Lovable, Bolt, Replit or Cursor on a Supabase backend. If your stack is Firebase, swap section 1 for Firebase rules basics.

Two principles behind every item: anything in the browser is visible and editable by the user, and a rule you haven’t tested as a second user is a rule you don’t know works.

1. Data access

  • Row level security is on for every table in public. Query in Step 1 of the database guide. (PL-008)
  • No table with personal data is readable by a logged-out visitor. Test with the anon role. (PL-001)
  • No table with personal data is readable by a stranger who signed up. This is the one most often missed: to authenticated using (true) looks safe and isn’t. (PL-002)
  • Strangers can’t change or delete other people’s rows, and update policies have WITH CHECK. (PL-012, PL-004)
  • Views run as the caller (security_invoker = true) or expose only public columns. (guide)
  • Tables published to Realtime have tight read policies. (guide)
  • All of it is in supabase/migrations, not only in the dashboard, so it can be rebuilt and re-tested.

How to test: the three-identity script in RLS policies explained.

2. Keys and secrets

  • No Supabase service role or secret key anywhere in frontend code or in a VITE_ / NEXT_PUBLIC_ variable. (PL-010)
  • No AI, payment or database secret in the code. They live in server-side secrets. (PL-009)
  • No secret in git history. Any that ever were are rotated. (PL-011, guide)
  • The built bundle is clean: npm run build, then search dist/ for sk_live_, sk-proj-, sk-ant-, service_role.
  • .env files are ignored, with a .env.example committed instead.

3. Sign-in, roles and admin

  • Email confirmation is on in your project’s authentication settings. (PL-018)
  • Roles are not in user_metadata. Use app_metadata or a roles table. (PL-019, guide)
  • Users can’t write their own role: no insert policy on the roles table for users, no role column in what users may update. (PL-013)
  • Admin pages are backed by admin-only database rules, not just a route guard. (PL-020)
  • No access decided by email domain or a hard-coded email address.

4. Server code

  • Every Edge Function verifies its caller with getUser(), a signature or a shared secret. (PL-017, guide)
  • No function takes a user id from the request body. (PL-022)
  • Payment webhooks verify signatures over the raw body. (PL-021, guide)
  • Cookie-authenticated endpoints don’t reflect any origin with credentials. (PL-026)
  • security definer functions have set search_path = '' and aren’t executable by anon unless meant to be. (PL-006)

5. Files, frontend and dependencies

  • Personal files are in private buckets with per-user folder policies, shown through signed URLs. (PL-007, PL-015, guide)
  • User content isn’t rendered as raw HTML, or is sanitised first. (PL-024)
  • npm audit --omit=dev shows no high or critical advisories you haven’t looked at. (PL-023, guide)

6. Run Supabase’s Security Advisor

In the Supabase dashboard, open the Security Advisor and clear what it reports. It catches several items above (RLS off, mutable function search paths, owner-rights views, policies that read user_metadata). It deliberately doesn’t judge public reads, because only you know which tables are meant to be public, which is why section 1 asks you to test as a stranger yourself.

7. After launch

  • Re-check after every round of AI changes. One prompt can rewrite a policy.
  • Know your first hour. Read what to do in the first hour after a leak now, not during one.
  • Give security reports somewhere to go: a contact address on your site.

Sources

The checks behind this guide, each with example code, a self-check and the fix.

Free check

Check your app for this, free.

Paste your public repo. PatchLabs rebuilds your database from its migrations, tests it as a visitor, a stranger and the owner, reads the code for keys and risky patterns, and hands you the fix.

Free for your first appNever touches your database

Written by Manraj Singh Dhillon. Last checked 10 Nov 2026. Code samples are synthetic and run against your own project; nothing here names a real app. Spotted a mistake? Tell us.