We look at a lot of vibe-coded launch pages. Same handful of mistakes shows up every week, across Lovable, Bolt, v0, Cursor, and Replit. None of these are exotic. All of them are fixable in an afternoon.
1. Secret keys sitting in the browser bundle
The AI helper wrote const openai = new OpenAI({ apiKey: "sk-..." }) in a file that eventually got imported into a client component. It builds. It runs. It also ships your key inside the JS bundle every visitor downloads.
Fix: any call that uses a secret happens on the server. Server functions, edge functions, or an API route — never a client component. Rotate the key immediately after moving it.
2. Service-role keys treated like anon keys
The service_role key bypasses row-level security. If it ends up in a client component, an env var prefixed VITE_ / NEXT_PUBLIC_, or a public edge function, anyone can read and write every row in every table.
3. RLS is off, or on with a "true" policy
The database has row-level security disabled entirely, or it's enabled but the policy is USING (true). Either way, anyone with your public URL and the anon key can list every row in the table.
4. Signup + tables without ownership
You can create an account. You can also read every account. There's no auth.uid() = user_id filter, so once someone is signed in, they see everyone's data.
5. Storage buckets set to public
Files uploaded through the app end up in a public bucket. Predictable filenames — user IDs, sequential integers — make them enumerable.
6. Webhooks with no signature verification
The Stripe webhook or GitHub webhook accepts any POST to /api/webhooks/stripe. Whoever hits it can mark themselves as a paying customer.
7. Admin UI behind a client-side check
The admin page renders {isAdmin && <AdminUI />}. Turn off the isAdmin flag in the browser dev tools and there's the admin UI. Real admin checks live in your API layer, not in JSX.
How WeVibe checks for this stuff
We fetch the same HTML and JS your visitors download and run a bunch of pattern matches for known key formats and template fingerprints. It's the passive equivalent of opening devtools and searching the bundle. We never write, we never log in, we never touch anything requiring auth. Every finding is labeled "worth checking" — the point is to catch the obvious ones fast.