Fix it: security problems in AI-built apps
You have a problem now. Each page tells you what it means, how to confirm it, and the exact steps to fix it.
Start with the problem you see now. Each page below names one symptom. It tells you what the symptom means, how to confirm it, and the steps to fix it in order of urgency.
If you do not know the cause, use this order:
- Money or keys at risk: a bill spike, a leaked key, or a key in your frontend. Revoke the key first.
- Data at risk: users see other users’ data, or a table is open to anyone. Close access first, then check the damage.
- Warnings with no attack yet: a Supabase Security Advisor warning or a scan finding. Fix these before someone finds them.
Leaked keys and secrets
- OpenAI API key exposed in the frontend: how to fix it: Any OpenAI key in browser code is public.
Supabase
- Anyone can delete rows in my Supabase table: how to fix it: A Supabase table with no RLS or a delete policy of true lets any caller delete rows.
- How to rate limit the Supabase API: Supabase limits only its Auth endpoints by default.
- Supabase Auth OTP long expiry warning: how to fix it: The warning means your Auth email OTP lasts too long.
- Supabase Edge Function with verify_jwt disabled: how to fix it: An Edge Function with verify_jwt false accepts any caller.
- Supabase RLS policy not working: why the query returns all rows: If a Supabase query returns all rows, find the cause: RLS off, a second open policy, a view, a service_role key, or a test as postgres.
- Supabase RPC function callable by anyone: how to fix it: Any role can run a new Postgres function by default.
- Supabase Realtime shows other users’ data: how to fix it: Realtime sends other users’ rows when RLS is off, a policy is too wide, or a channel is public.
- Supabase "RLS disabled in public" warning: how to fix it: The warning means anyone with your project URL can read, edit and delete the table.
- Supabase app hacked: what to do, in order: Find the entry point, turn on RLS, rotate the keys and the database password, sign out users, then read the logs to see what the attacker took.
- Supabase error: infinite recursion detected in policy: The error means a policy reads its own table.
- Supabase leaked password protection disabled: how to fix it: The Supabase security advisor warns when leaked password protection is off.
- Supabase profiles table exposed: how to lock it down: If anyone can read your Supabase profiles table, remove the open policy, move private columns to a protected table, and test the API as an anonymous caller.
- Supabase security definer view warning: how to fix it: A view in the public schema bypasses RLS by default.
- Supabase storage bucket is public: how to make it private: A public Supabase bucket serves every file to anyone with the URL.
- Supabase storage file URLs are guessable: how to fix it: A public Supabase bucket has no access control on downloads.
- Supabase table data deleted by someone: recover it and stop it: Revoke delete access, restore the rows from a backup into a new project, copy only the missing rows back, then read the logs to find who deleted them.
- Supabase users can sign up without confirming their email: the fix: Turn on Confirm email in the Supabase email provider settings, set up custom SMTP, and remove the fake accounts that signed up without a confirmed address.
- Supabase warning: function search_path mutable: The warning means a function has no fixed search_path.
Login and accounts
- A user can change their role to admin: how to fix it: If a user can write their own role, the user can become admin.
- A user changed their email and lost the account: how to fix it: An email change without confirmation lets an attacker take an account.
- Admin page accessible without login: how to fix it: If /admin opens without a login, the server does not check the user.
- Clerk API route not protected: how to fix it: Clerk middleware does not block an API route by itself.
- Credential stuffing attack signs: how to find it and stop it: Many failed logins across many emails from few sources signal credential stuffing.
- How to stop anyone from signing up to your internal app: Hiding the sign-up button does not block sign-ups.
- Is storing a JWT in localStorage safe? What to do instead: No.
- Magic link logs into the wrong account: how to fix it: A magic link that opens another user’s account is a session bug.
- NextAuth middleware not protecting routes: how to fix it: NextAuth middleware only protects the paths in its matcher.
- OAuth redirect URI wildcard: the risk and how to fix it: A wildcard redirect URI can send login codes to an attacker.
- Password reset link never expires: how to fix it: A reset link that works after days or after use is an account takeover risk.
- Session still valid after logout: how to fix it: A logout that only clears the browser leaves the session alive on the server.
- Someone is brute forcing logins on your app: how to stop it: Many failed logins in your logs mean a brute force attack.
- Users logged in as someone else: how to find the cause and fix it: If users see another account, a shared cache or a shared server variable is the likely cause.
AI features and coding agents
- AI agent deleted my production database: how to recover: Stop all writes, copy the damaged database, then restore from a backup or point-in-time recovery.
- AI chatbot jailbroken on your site: how to fix it: If users make your AI chatbot say off-brand things, limit what it can do, filter input and output, add rate limits, and log every chat.
- AI response renders HTML: how to fix the XSS: Treat model output as untrusted text.
- Cursor agent ran a dangerous command: what to do now: Stop the agent, find what the command changed, restore from git or a backup, then move Cursor out of Run Everything mode and limit what the agent can reach.
- How to rate limit an AI endpoint for each user: Check the login, then count the calls of each user ID.
- How to stop Claude Code from reading your .env file: Add Read deny rules for .env files in .claude/settings.json, turn on the sandbox for shell commands, and rotate any secret that Claude Code already read.
- MCP server exposed to the internet: how to fix it: An MCP server with no login lets anyone run its tools.
- People use my AI app as a free ChatGPT: how to stop it: Your AI route is an open proxy.
- Prompt injection through uploaded files: how to fix it: Treat every uploaded file as untrusted text.
- RAG chatbot leaks other users’ documents: how to fix it: A RAG chatbot leaks documents when retrieval has no owner filter.
- Unexpected OpenAI bill spike: how to find the cause and stop it: Check the OpenAI usage page, delete the key that spends, set a hard spend limit, then add per-user budgets and token caps to the server route.
- Users extracted my system prompt: what to do now: You cannot keep a system prompt secret.
Lovable, Bolt, Replit and other builders
- Base44 app data exposed: how to check and lock it down: Base44 entities with no RLS rules are open to all users.
- Bolt.new app with Supabase RLS missing: how to fix it: Check each table of your Bolt Supabase project for RLS.
- Bubble data exposed because privacy rules are not set: how to fix it: A Bubble data type without privacy rules can be read by anyone.
- Lovable GitHub repo is public: make it private and rotate secrets: Set the repository to private in GitHub, rotate every secret that the code or history held, check forks and logs, then remove old secrets from the history.
- Lovable app hacked: what to do, in order: Take the app offline, close the database with RLS, replace the leaked keys, make the GitHub repo private, then read the logs to see what the attacker did.
- Lovable app shows everyone’s data: how to fix it: If your Lovable app lists the rows of all users, the table has no owner rule.
- Lovable edge function public without auth: how to lock it down: Anyone can call an edge function that has no auth check.
- Lovable security scan found issues: what to do next: Sort Lovable scan findings by severity, fix Critical items first, test each fix from outside the app, and ignore a finding only with a written reason.
- Replit database publicly accessible: how to find the cause and fix it: A Replit database is public when the connection string leaks or when your app API returns its rows.
- Replit deployment leaking secrets: how to find and fix it: A secret that reaches the browser, a public file, or a log is leaked.
- SQL injection in Cursor-generated code: how to find and fix it: Find queries that join user input into SQL text, replace them with parameters, and add a Cursor rule so new code stays safe.
- V0 app API route unprotected: how to find and fix it: A Next.js route handler is public until it checks the user.
Data leaks and broken access
- API returns password hashes or too many fields: how to fix it: An API that returns whole database rows leaks hashes and private fields.
- CSV export leaks all users: how to find the leak and fix it: An export endpoint that skips the owner filter returns every row.
- File upload accepts any file type: how to find the cause and fix it: The accept attribute does not block files.
- GraphQL introspection enabled in production: how to fix it: Introspection shows your full schema to any caller.
- Link preview fetches internal URLs: how to fix the SSRF: A link preview that fetches any URL can reach your private network.
- Open redirect on the login page: how to fix it: A login page that sends users to any next URL helps phishing.
- SQL injection in AI-generated code: how to find it and fix it: AI tools often build SQL with string concatenation.
- Sequential IDs security risk: what to fix first: Sequential IDs are a risk only when the server skips the owner check.
- Swagger docs public in production: how to close them: Public Swagger or OpenAPI docs list every route of your API.
- User uploads publicly accessible: how to fix it: Any file in a public bucket opens for anyone with the URL.
- Users can see other users’ data: how to find the cause and fix it: If one user can read another user’s rows, the server does not check the owner.
- XSS from user markdown content: how to find it and fix it: User markdown that renders raw HTML runs attacker scripts in other browsers.
/ NEXT STEP
Scan your deployed app
Paste your live URL. VibeEval probes exposed keys, missing auth, open databases, and broken access control - results in under 60 seconds.
14-day free trial · No credit card · Cancel anytime