Security before you launch
The honest pre-launch checklist: exposed API keys, missing row-level security, broken auth — the mistakes that are epidemic in vibe-coded apps and how to check for each one.
10 min read · Last verified
Security is the place where vibe coding's honest limitation lives. AI tools write code that works far more reliably than code that's safe — the app runs, the demo dazzles, and the API key is sitting in public view. Exposed keys and wide-open databases are genuinely epidemic in vibe-coded apps, and attackers know it: new deployments get scanned by bots within hours.
This is the checklist we'd want every VibeStar project to pass. None of it requires becoming a security expert. All of it can be driven by asking your AI the right questions — the same skill you already have.
When to run it: before anything real touches the app. A toy with no accounts, no database, and no secret keys can skip most of this. The moment there are users, data, or paid API keys involved, it's mandatory.
1. Secret keys don't belong in the code
API keys (OpenAI, Stripe, Resend, maps…) are passwords that spend money. Two rules:
- Secrets live in environment variables — settings configured on your hosting platform — never typed into code files, and never committed to git. (If a key ever got committed, it's compromised: revoke it and make a new one. Deleting the line later doesn't help; git history and scrapers are forever.)
- Anything that reaches the browser is public. Frontend code, even "hidden" in a bundle, is readable by anyone. Calls that use secret keys must happen server-side.
Ask your AI: "Audit this project for API keys, passwords, or secrets in the code or git history. Are any secrets exposed to the browser bundle?"
2. The database has to enforce its own rules
The classic vibe-code disaster: the app dutifully shows users only their own data, but the database answers any question from anyone. Attackers don't use your app's screens — they call the database's API directly with the public credentials shipped in every browser.
The fix is server-enforced access control. On Supabase and similar platforms this is row-level security (RLS): rules attached to each table — "users can read only rows where user_id matches their own." With RLS off (or on with sloppy rules), your public key is an all-access pass to every user's data.
Ask your AI: "For each database table, tell me: is RLS enabled, and what do the policies allow an anonymous visitor and a logged-in user to read and write? Look for tables readable or writable by anyone." Supabase's dashboard also has a built-in security advisor that flags unprotected tables — run it.
3. Auth: the server can't trust the browser
Login checks belong on the server. Code like "if user is admin, show admin page" running only in the browser isn't security — anyone can open dev tools and flip that flag. Every server endpoint that changes data must itself verify who is calling and whether they're allowed, every time.
Ask your AI: "List every server endpoint and action in this app. For each: does it verify the caller's identity and authorization on the server? Which ones would work if called directly with curl by someone who isn't logged in?" (That last question is the one that finds the horrors.)
Use your platform's real auth system (Supabase Auth, Clerk, NextAuth…) — never let the AI hand-roll password storage. If it wrote its own password hashing, replace it.
4. Don't trust anything users type
Every input box is a door. The big three to check:
- Injection: database queries must use your platform's query builder or parameterized queries — never text glued together with user input.
- XSS: user text must be displayed as text, not rendered as HTML.
Frameworks default to safe here; the AI escape hatches (like React's
dangerouslySetInnerHTML) are findable by name — search for them. - Limits: lengths capped, types validated, uploads restricted by size and type — enforced on the server, not just in the form.
Ask your AI: "Check every place user input reaches the database or the page. Any string-concatenated queries, unsanitized HTML rendering, or inputs without server-side validation?"
5. Rate limits, or your inbox/API bill will find out
Anything free to call will be called a million times by a bot: signup forms, email senders, AI-powered endpoints. Add rate limiting to public endpoints — especially anything that sends email or calls a paid API — and set a spending cap or billing alert on every external service the moment you add its key.
The meta-lesson
Notice the pattern in every prompt above: you're not asking the AI to write code, you're asking it to audit code — a different mode it's markedly better at when explicitly asked. The most dangerous phrase in vibe coding is "it works, ship it." The most valuable is: "What's wrong with this?"
Run the checklist, fix what it finds, and then — publish with a clear conscience. Trust is a feature, and your users can't audit your code. You just did it for them.