I keep finding the same 5 security holes in AI-built apps. Here's the list + fixes.
I review a lot of apps built with Cursor / Lovable / v0 / Bolt, and the same
handful of security holes show up almost every time. None of it is the
builder's fault — it's just what the tools leave behind. Sharing the pattern in
case it saves someone a bad week.
1. Open database (the #1 by far)
Supabase with Row-Level Security off, or Firebase rules left wide open. Your
frontend ships the public anon key, so if RLS is off, anyone who opens devtools
can read/write every table. Fix: turn on RLS and write per-table policies, then
test with the anon key from an incognito tab — if you can still read data you
shouldn't, it's open.
2. Secret keys in the frontend bundle
OpenAI / Stripe / service-role keys pasted into client code or pushed to a
public repo. Bots scrape new commits within minutes. Fix: the only key allowed
in the browser is the public/anon one. Everything else goes server-side (an
edge function / API route). Rotate anything that's ever been committed.
3. "God-mode" endpoints + IDOR
The AI generates routes but forgets authorization — an admin endpoint you can
hit without logging in, or /api/orders/1234 where changing the number returns
someone else's data. Fix: check auth AND ownership on every endpoint, not just
"is this person logged in."
4. Injection in generated routes
String-concatenated SQL and unescaped output → SQLi / XSS, the classic
database-dumping bugs, shipped by default. Fix: parameterized queries and your
framework's escaping. Never build a query by concatenation.
5. Prompt-injectable AI feature
The chatbot you bolted on will leak its system prompt or call tools it
shouldn't the moment a user says "ignore previous instructions." Fix: treat
model output as untrusted, don't wire the model straight to your DB/tools
without guardrails, and keep secrets out of the system prompt.
(Disclosure: I build a scanner for exactly this, so I see these a lot — but the
list above stands on its own, no link needed.)
Curious what everyone else sees: which of these bit you, or is there a 6th I'm
missing? And for the open-database one — is anyone running automated checks for
RLS being off, or is it all manual review right now?
Replies
Let me add #6: costly endpoints with correct auth but no abuse controls. An endpoint can check ownership perfectly and still let one user trigger 1k of OpenAI or TTS calls. I treat auth as only the first gate. Every expensive path also gets bounded input and its own rate limiter.
Regarding a credit race. If you check a balance and decrement it in two queries, parallel requests can both pass. The debit needs to be one conditional database update. That concurrency case is easy to miss because the endpoint is authorized and behaves correctly under a single request.
My 6th is the one that only shows up at deploy time: secrets that were fine in .env locally get inlined into the client bundle because the agent prefixed them with NEXT_PUBLIC_ or VITE_ to make the build stop complaining. I've caught real API keys sitting in a shipped JS chunk that way. On RLS I don't trust manual review - I keep a small script that hits each table anonymously and fails CI if any of them return rows, which is crude but catches "RLS off" every time.