Vibe Coding Security: What AI Ships Broken (and How to Catch It)

The specific security holes AI coding tools produce by default — exposed keys, missing authorization, open APIs — and a checklist to find them before launch.

C
CodeIllusion Team
#vibe-coding #security #ai-coding-tools #saas
Vibe Coding Security: What AI Ships Broken (and How to Catch It)

The problem with security bugs is that they don’t announce themselves. An app with no authorization checks works perfectly. It loads, it saves, it looks finished. The failure is invisible right up until someone finds it.

That’s why AI coding tools produce them so reliably. These tools optimise for code that runs, and every flaw below leaves code that runs perfectly.

This isn’t an argument against vibe coding. It’s the specific list of what to check before anything you built this way meets real users.

1. Authorization vs Authentication

The single most common flaw, by a wide margin.

Authentication is “who are you.” AI tools get this right almost every time — login works, sessions persist, protected routes redirect.

Authorization is “are you allowed to touch this specific thing.” This gets skipped constantly.

The result looks like this. You build a dashboard where users see their own invoices. The AI writes an endpoint at /api/invoices/[id]. It checks you’re logged in. It does not check the invoice belongs to you.

/api/invoices/1041   ← your invoice
/api/invoices/1042   ← someone else's invoice, also returned

Everything works. Every test passes. Every user can read every other user’s data.

How to check: Make two accounts. Log in as the first, note a record ID. Log in as the second and request the first account’s ID directly. If you can see it, you have this bug.

What to ask for:

Every query that reads or writes user-owned data must filter by the authenticated user’s ID at the database level, not just in the UI. Show me each place this is enforced.

2. Exposed Secrets

AI tools place API keys wherever the code is simplest, which is often the browser.

Three specific traps:

NEXT_PUBLIC_ variables are public. The prefix means “ship this to the browser.” An AI that hits an environment variable error will sometimes fix it by adding that prefix. Now your key is in the JavaScript bundle, readable by anyone who opens devtools.

Keys committed to Git. If it was ever in a commit, it’s in the history. Deleting it from the current file does nothing. Rotate the key.

Server keys used client-side. Supabase’s service_role key bypasses all row-level security. It belongs on the server only. It ends up in frontend code more often than you’d hope.

How to check:

git log -p | grep -iE "sk-|api[_-]?key|secret|password" | head -40

Then open your deployed site, view source, and search the bundle for key, sk-, and secret.

3. Row-Level Security Left Off

If your app uses Supabase, Firebase, or a similar hosted database, this one matters enormously.

These platforms expose the database directly to the browser. What stops a user reading the whole table is row-level security policies. AI tools generate working apps without enabling RLS all the time — because enabling it while the app is half-built causes errors, and the path of least resistance is to leave it off.

An app with RLS disabled and a public anon key means anyone can query your entire database from their browser console. Not your API. Your database.

How to check: In Supabase, open Table Editor and look for the RLS badge on every table. Any table without it is fully readable.

What to ask for:

Enable row-level security on every table and write policies so users can only select, insert, update, and delete their own rows. Show me the SQL.

4. No Input Validation

AI-generated forms validate in the browser and trust whatever arrives at the server. Browser validation is a convenience for honest users; it stops nobody who opens a terminal.

This produces oversized uploads, malformed data that corrupts your tables, and injection where the input reaches a query or a template.

What to ask for:

Validate every API input server-side with Zod. Reject anything that doesn’t match the schema before it reaches the database. Include maximum lengths on all string fields.

5. Open Endpoints and No Rate Limiting

If your app calls an AI API, sends email, or does anything that costs money per request, an unprotected endpoint is a billing incident waiting to happen.

The pattern: you build a tool that calls a language model. The endpoint is public because it needs to work before login. Someone finds it and loops it. You discover this via your invoice.

What to ask for:

Add rate limiting to every public endpoint — per IP and per user. Any endpoint that calls a paid API must require authentication and enforce a per-user quota.

6. Errors That Say Too Much

Default error handling returns stack traces, file paths, database schema, and sometimes connection strings. Useful while building; a map of your system in production.

What to ask for:

In production, return generic error messages to the client and log details server-side only. No stack traces in any API response.

7. Dependencies Nobody Chose

Agentic tools install packages to solve problems. Some are unmaintained, some are near-typosquats of the package they meant.

npm audit

Run it. Then read your package.json and confirm you can say what each entry is for. If you can’t, you didn’t choose it.

The Pre-Launch Checklist

Before anything you vibe coded touches real users:

  • Two test accounts — confirm neither can access the other’s records by ID
  • git log -p | grep -i "key\|secret" returns nothing sensitive
  • No secrets in the client bundle (view source and search)
  • Row-level security enabled on every table, with policies
  • Every API input validated server-side
  • Rate limiting on all public endpoints
  • Any paid-API endpoint requires auth and has a per-user cap
  • Generic error messages in production
  • npm audit clean, and you recognise every dependency
  • Logged out, tried to call your API directly — got rejected

Using AI to Audit AI

This works better than it sounds, because reviewing is an easier task than building and you can point it at one thing at a time.

Review this file as a security auditor. For every database query, tell me whether it filters by the authenticated user. List anything a logged-in user could access that isn’t theirs. Don’t fix anything yet — just report.

Asking it to report rather than fix keeps it from quietly rewriting things while you’re trying to understand them. Do this file by file for anything handling data, auth, or payments.

It won’t catch everything. It will catch the obvious tier, which is where most of these bugs live.

The Rule Worth Keeping

Vibe code freely up to the point where a stranger can reach it. At that boundary, read the code.

That’s not a limit on how much you can build this way — it’s most of an app. It’s a limit on which parts you ship without looking, and it’s the difference between a tool that works and a tool that quietly leaks.

Related reading:

Frequently Asked Questions

Is vibe coding secure? +

Not by default. AI coding tools optimise for working code, and security flaws don't stop code from working. The most common results are missing authorization checks, exposed API keys, and endpoints with no rate limiting — none of which are visible from using the app.

What is the most common vibe coding security mistake? +

Confusing authentication with authorization. AI tools reliably check whether someone is logged in, and routinely fail to check whether that specific user is allowed to access that specific record. The result is an app where changing an ID in the URL shows you someone else's data.

Can I put a vibe coded app in production? +

Yes, if you review the security-critical parts first. The code itself is often fine. What's missing is the layer that doesn't affect whether the app works — access control, input validation, rate limits, and secret management. Those need a human pass.

How do I check if my AI-generated app is secure? +

Start with four checks: try accessing another user's record by changing an ID, look for secrets in your repo and client bundle, confirm database row-level security is enabled, and call your API endpoints directly without logging in. Most AI-generated apps fail at least one.

Do AI coding tools leak API keys? +

They frequently place keys where they end up in the browser bundle or committed to Git. Anything in a NEXT_PUBLIC_ variable is public. If a key has ever been committed, rotate it — removing it from the current code doesn't remove it from Git history.

Tagged:

#vibe-coding #security #ai-coding-tools #saas

Enjoyed this article?

Get more AI tool picks, coding tutorials, and no-code automation guides every week. No spam, ever.

Found this useful? Share it:

More in AI Coding Tools