Skip to content

Is Vibe Coding Safe? How to Find and Fix the Security Holes in an AI-Built App

· 8 min read

Is vibe coding safe? It can be, but most vibe-coded apps that ship today are not, because AI tools write code that works long before they write code that is secure. The good news is that the holes follow a pattern, and you can check your own app for them in an afternoon.

If you built an app with an AI coding tool, got it running, and pushed it live, this one is for you. The question is fair, and the honest answer is more useful than "it depends."

Everything below is about auditing your own app, or one you have explicit written permission to test. Do not point any of this at someone else's project.

Is vibe coding a security risk? Here is what people keep finding

You do not have to guess. People in the community have been scanning live vibe-coded apps and posting the results, and the numbers are not great.

One public scan looked at 30,998 live vibe-coded apps and found 394 with a users table anyone could read, plus 52 exposing secrets. That is hundreds of apps where a stranger with a browser could pull user records.

A smaller scan of 48 vibe-coded apps found that about 90% had at least one vulnerability. The list included SECURITY DEFINER misuse in database functions and broken object-level authorization (BOLA, also called IDOR), where changing an ID in a request gets you someone else's data.

And when practitioners compare notes, the same short list keeps coming up. One widely discussed thread on vibe coding security issues puts it at roughly 80% of problems coming from five things:

  • Exposed environment variables and API keys
  • Missing row-level security
  • No server-side validation
  • Outdated or hallucinated packages
  • No auth middleware

Other threads on the flaws people keep seeing and the backend basics that matter most land in the same place. So is vibe coding a security risk? The practice itself is not the problem. Shipping without checking is.

Why AI-built apps keep shipping the same holes

This is not because the models are dumb. It is because of what you asked for and how you checked it. The model optimizes for "it runs," so nobody asked for an authorization check and there often is not one. Client-side database calls make the demo work in one step and also mean the browser is trusted, which it should never be. Demo defaults (open tables, broad keys, permissive CORS) stay that way when you ship. And you did not read every line, which is sort of the point of vibe coding, and also means nobody reviewed the parts that matter.

Once you know the pattern, fixing it is mostly mechanical.

Vibe coding security risks: the five that cause most of the damage

1. Exposed env vars and API keys

A secret key ends up in frontend code, a public repo, or a build bundle. In many frameworks, any variable with a public prefix (like NEXT_PUBLIC_ or VITE_) is baked into the JavaScript every visitor downloads. Some keys are meant to be public, like a Supabase anon key, and that key is only safe if row-level security is doing its job. A service role key, a payment secret, or an AI provider key is never safe in the browser.

2. Missing row-level security

If your app talks to Postgres from the client (common with Supabase), row-level security (RLS) stands between your users and each other's data. If RLS is off, anyone holding the public key can read the table. That is how you end up with a users table anyone could read. Watch for SECURITY DEFINER functions too: they run with the creator's privileges and usually skip RLS. An AI tool may reach for one to "fix" a permissions error and quietly open the table back up.

3. No server-side validation

If the only checks live in your React form, they are suggestions. Anyone can hit your API with a negative price, someone else's user ID, or a role set to "admin." Validation and authorization have to happen on the server every time. This is where BOLA and IDOR live: /api/orders/1234 works, so does /api/orders/1235, and the server never asks whether order 1235 belongs to you.

4. Outdated or hallucinated packages

Models sometimes suggest packages that are old, unmaintained, or do not exist. A package name that does not exist today can be registered by someone else tomorrow, and then your install pulls their code. Outdated packages carry known public vulnerabilities.

5. No auth middleware

Pages hide the admin button, but the admin route still answers anyone who calls it. Without middleware (or a check at the top of every protected handler) that verifies the session and role, your "private" API is public with extra steps.

How to secure vibe coded apps: a self-audit you can run today

Again, this is for your own app. Block out a couple of hours and work through it in order.

Step 1: Hunt for secrets. Search your repo, your production build output, and your git history for anything that looks like a key. Deleting a key in a later commit does not remove it from history.

# Run in your own project. Patterns are examples, add your providers.
grep -rEn "sk_live_|sk-|service_role|SECRET|PRIVATE_KEY" --include=*.{js,ts,tsx,env} .
grep -rEn "sk_live_|service_role" .next/ dist/ build/ 2>/dev/null

If you find a real secret anywhere public, rotate it first. Then move it to a server-only environment variable.

Step 2: Check RLS on every table. In Supabase, this query lists tables in the public schema with RLS off:

select tablename
from pg_tables
where schemaname = 'public' and rowsecurity = false;

Every table on that list needs RLS enabled and a policy. A typical "users can only see their own row" policy looks like this:

alter table profiles enable row level security;

create policy "read own profile"
on profiles for select
using (auth.uid() = id);

Then list your SECURITY DEFINER functions and ask whether each one really needs to bypass RLS.

Step 3: Test it like an outsider. Log out and try to read data with only what the public site ships. Then make two test accounts and try to fetch account B's records while logged in as A by changing IDs. If it works, you found a BOLA bug in your own app.

Step 4: Move validation to the server. For every write endpoint, check the session, check ownership, and validate input against a schema. Reject anything you did not expect.

Step 5: Audit your dependencies. Run your package manager's audit, update what you can, and confirm every package is real. If you have never heard of a package the AI added, look it up before you keep it.

Step 6: Protect every route. Add auth middleware, then confirm every API route either requires a session or is deliberately public.

Vibe coding security checklist (copy this)

Paste this into your notes and tick it off before every launch:

  • No secret keys in frontend code, build output, public repos, or git history
  • Only keys designed to be public are exposed to the browser
  • RLS enabled on every table, with a policy for each operation you allow
  • SECURITY DEFINER functions reviewed and justified
  • Every write validated on the server against a schema
  • Every request checks that the user owns the record (no BOLA or IDOR)
  • Dependencies audited, updated, and confirmed to be real packages
  • Auth middleware in front of every non-public route
  • Admin actions checked by role on the server, not hidden in the UI
  • Tested with two accounts and a logged-out browser

Use AI to audit the AI's code (carefully)

The same tools that wrote the code can help you review it, if you brief them well and verify what they say. Tell the model it is your app, what stack you used, and what to check. See write a prompt that works first try for why that context helps.

Context: This is my own app. I built it and I am auditing it before launch.
Stack: Next.js, Supabase, Stripe.
Task: Review the files below for these five issues only:
exposed secrets, missing RLS, missing server-side validation,
risky or nonexistent packages, and unprotected routes.
For each finding, quote the exact line and explain how to confirm it.
If you are not sure, say so. Do not guess.

Treat every answer as a lead, not a verdict. Models miss things and invent things. Confirm each one by testing it yourself.

If your app has AI features of its own (a chatbot, an agent, anything that reads user content), you have a second class of risk. Read the prompt injection defense checklist before you ship it.

Want prompts already written for this? The Free Authorized Testing Kit includes field-tested prompts for authorized security testing. The AI Red Teaming Prompt Playbook ($79) has the full set organized by phase, including access control review, testing your own LLM apps, and a chapter on knowing when to trust the model.

So, is vibe coding secure enough to ship?

It can be. The apps getting burned are not failing because AI wrote them. They are failing because nobody checked the five boring things. Run the checklist, fix what you find, and re-run it every time you let the AI touch your auth or database code.

FAQ

Is vibe coding safe for production apps?

It can be, if you review the security basics before launch. Community scans show many live vibe-coded apps ship with exposed data or secrets, so treat a security pass as a required step, not an extra.

Is vibe coding secure if I use Supabase or Firebase?

The platforms are fine. The risk is configuration. With Supabase, the public anon key is only safe when row-level security is on for every table and your policies are correct.

What is the most common vibe coding security risk?

Practitioners point to five recurring issues: exposed keys, missing row-level security, no server-side validation, bad packages, and missing auth middleware. Exposed data from missing RLS is one of the most damaging.

Can AI find security bugs in its own code?

It can help, if you give it clear context and a specific checklist. It also misses issues and reports false ones, so confirm every finding by testing your own app.

Can I scan other people's vibe-coded apps for these flaws?

Only with explicit written permission or inside a bug bounty program's published scope. Audit your own app freely. For anyone else's, get permission first and disclose responsibly.

Keep reading