BusiRocket

Article

Security checklist for vibe-coded apps: RLS, exposed keys, auth and GDPR

Published on

Security is the part of an AI-built app that fails silently. A broken deploy announces itself with a blank screen; a Supabase table without Row Level Security announces nothing — everything works, users are happy, and any of them could read the whole database. The incidents that made the rounds in the vibe-coding world (exposed API keys burned within hours of a public launch, databases readable by any visitor) all share that shape: nothing looked wrong.

This is the checklist we run against every AI-generated app that reaches us, whether it came from Lovable, Bolt, v0, Base44, Replit, or a Claude Code or Codex session. You can run most of it yourself in an afternoon.

1. Row Level Security: prove it, don't trust it

If your app uses Supabase (most do), RLS is the wall between users' data. The failure mode is not "RLS missing" — it is policies that read like protection and enforce nothing, because an AI wrote something plausible.

  • Every table containing user data has RLS enabled.
  • Every table has explicit policies for select, insert, update, delete — a table with RLS on and no policies denies everything, which breaks the app; the AI's usual "fix" is a policy that allows everything, which breaks you.
  • The two-account test: create two accounts, then try to read and modify account A's data while logged in as B — from the app, and directly against the API with B's token. This test beats any amount of policy reading.

2. Secrets: anything in the browser is public

Open your deployed app, view source, search for sk_, key, secret, token. Anything that ships to the browser — including every variable prefixed NEXT_PUBLIC_ or VITE_ — is readable by anyone.

  • Stripe secret keys, OpenAI keys, Supabase service_role keys: server side or edge functions only, never in frontend code.
  • A key that was ever exposed is burned: rotate it, don't just move it.
  • Check the git history too — a key committed once is still in the history after you delete the line.

3. Authorization: hiding a button is not a permission

AI tools are consistent about this failure: the admin panel checks if (user.isAdmin) in the interface, and the API route behind it checks nothing. Every rule about who can do what must execute on the server, at the point where data is read or written, and hold even when someone calls the API directly with curl and a valid session token. If a permission only exists in the UI, it does not exist.

4. The boundaries: payments, uploads, email

  • Stripe webhooks: verify the signing secret and make handlers idempotent — Stripe retries, and a retried event must not grant a second subscription.
  • File uploads: limit size and type server-side, and store user uploads where they cannot be executed or enumerated.
  • Email flows: password-reset and magic-link tokens should expire and be single-use. AI-generated implementations frequently miss both.

5. GDPR, because your users are probably in the EU

If any user is in the EU, this stops being optional paperwork:

  • Know where the data physically lives (your Supabase project has a region — check it) and what third parties receive it. Sending user content to an LLM API makes that provider a processor too.
  • A privacy policy that reflects what you actually collect and can honour a deletion request — an AI-generated app that scattered user data across services makes "delete this user everywhere" genuinely hard.
  • Don't log personal data or tokens into analytics and error trackers.

As an EU studio this is home turf for us, and it is the check most US-based rescue services quietly skip.

What to do with the failures you find

Alone, none of these is a reason to panic; unreviewed, together, they are why most AI-generated apps we audit have at least one serious hole. Fix order: exposed secrets first (rotate today), then RLS and server-side permissions, then webhooks and boundaries, then the GDPR housekeeping.

If you would rather have the whole review done by people who do it weekly, that is the first half of our vibe code rescue audit: 450 EUR, 48 working hours, every finding explained and priced. The other common entry points are the app breaking only in production or the rebuild-or-fix decision — the audit answers all three from one read of the code.

Next step

Does this problem sound like yours?

Tell us about it and we will say how we would approach it, in what order and at what cost.