Almost every data leak we see in a vibe-coded app traces back to the same short list. None of them are exotic attacks. None of them show up as a red checkmark — the app works perfectly, which is exactly why they survive to launch. Here are the seven worth checking before real users and real data go behind your app.
1. The database is open (RLS off)
The big one, especially on Supabase and Firebase. Row-level security is disabled, or a rule was set to true “just to get it working” and never tightened. Your public anon key — which is meant to be public — then becomes a key to every row in every table. It works flawlessly for you, because you only ever look at your own data. → How RLS quietly leaves your database open
2. A secret shipped to the browser
A STRIPE_SECRET_KEY, a service-role key, or an admin token gets bundled into the client-side JavaScript. Anyone can open DevTools and read it, then charge cards or read your whole database. → How to find the keys your app is leaking
3. Routes protected only in the UI
There’s a login screen, so it feels secure. But the /admin page hides the link instead of enforcing a check on the server. Type the URL directly and you’re in. Hiding a button is not access control. → Your /admin page isn’t actually protected
4. One tenant can read another’s data
In multi-tenant apps, the leak is a query that trusts an org_id sent by the browser, or filters on the client. Swap the ID in the request and you’re reading another customer’s invoices, messages, or records. This is the bug that becomes a headline — and the one scanners miss, because the code looks normal. → The bug that lets one customer read another’s data
5. Firebase still in test mode
Firebase’s default rules are wide open so you can build quickly — and the warning is easy to miss. Ship with allow read, write: if true and your entire database is readable and writable by anyone with your config. → Firebase in test mode: your database is public
6. No rate limiting where it matters
Login, signup, password reset, and any endpoint that sends email or costs money usually ship with zero limits. That opens the door to credential stuffing, brute force, and — on paid APIs — a bill that runs up while you sleep. It’s also a data-exposure path: unlimited login attempts are how accounts get taken over.
7. Errors that hand attackers a map
A verbose stack trace or raw database error returned to the browser leaks table names, file paths, query structure, and library versions — a free blueprint for whatever comes next. Convenient while debugging; a gift to an attacker in production. → When your app breaks, can you even tell?
The thread running through all seven
Every one of these works. The build is green, the demo is clean, and the flaw is invisible until someone who isn’t you interacts with the app. That’s the gap automated checks can’t close: a scanner doesn’t know that this route is the admin route or that this query crosses a tenant boundary. A person reading your actual code does. Run the free 2-minute self-check to see how many of the seven apply to you.
If more than one of these made you pause, that’s the signal to have the code read before you launch. That’s what a production-readiness audit is: a senior engineer reads your actual code, finds the leaks hiding behind green checkmarks, and tells you — in plain English — what to close first.