Why it happens
Why Supabase is where AI-built apps break
Every AI builder wires the same backend. Lovable, Bolt, Base44 and most Replit projects put Supabase behind the interface, which means the visible app is generated code and the thing holding your actual data is a database configured by the same process.
That configuration is where the gaps sit, for a specific reason: during development everything works, because you are logged in and looking at your own data. The problems only appear when a different user, an unauthenticated request, or a production environment enters the picture — which is usually after launch.
It's also the reason a Supabase problem rarely looks like a Supabase problem. It shows up as a login loop, a blank screen, a form that doesn't save, or an email that never arrives.
The failures
What we find
# | Failure | What's happening |
01 | Row-level security enabled, policy allows everything | The linter passes and the dashboard shows green, but a policy written as USING (true)grants every authenticated user access to every row. The check confirms RLS is on, not that it does anything. |
02 | Service role key in the client bundle | A key that bypasses every policy is shipped to the browser. Anyone can read it from the network tab and query the database directly, including tables the app never exposes. |
03 | RLS turned off to make a feature work | Enabling RLS without writing a policy denies everything, the feature breaks, and the quickest fix is to disable it or route around it. That fix is usually still in place months later. |
04 | Connected to the wrong project | The app is talking to a development project, an abandoned one, or a project whose keys were rotated. Nothing saves and no error explains why. |
05 | Auth redirect excludes the production domain | Login succeeds, the session is discarded on the way back, and the user lands on the login screen again. This is the loop your users are reporting. |
06 | Edge functions failing silently | Webhooks, confirmation emails and payment updates stop arriving. The function errors, nothing surfaces it, and the first signal is a customer asking where their receipt is. |
07 | Storage buckets public by default | Uploaded files — invoices, IDs, private images — are reachable by anyone with the URL, and URLs are guessable more often than people expect. |
08 | No foreign keys or constraints | The schema looks fine until orphaned rows, duplicates and impossible states accumulate. By then the data itself needs repairing, not just the code. |
09 | Queries inside render loops | Fine at fifty rows. The dashboard times out somewhere around two thousand, and connection limits start rejecting requests under real use. |
Worth knowing
Why the scanners miss it
Most security tooling for AI-built apps checks whether row-level security is enabled. That is a useful check and it is not the same question as whether your data is protected.
A policy that allows everything passes. A service role key in the client bundle passes. An app that queries with an elevated key passes. Every one of those leaves a database that anyone can read, and every one of them shows green.
Passing a scan and being safe are different results. Reading the policies is the only way to tell them apart.
The work
What we do
An engineer reads the policies, the keys, the auth configuration and the queries — then checks what the application actually does with them, because a correct policy and a query that bypasses it produce the same outcome as no policy at all.
You get the access-control gaps closed, the keys moved where they belong, auth working across environments, and a written record of what was wrong so it doesn't return the next time someone prompts a change.
We won't
✕ | Disable RLS to make a feature work |
✕ | Fix one policy and leave the rest untested |
✕ | Rewrite a schema that's doing its job |
Can you check this yourself?
Three tests, no tools required.
Test | How | What it means |
Cross-account read | Log in as a second user. Change the ID in a URL or an API call to one belonging to the first user. | If the data loads, your access control is not working. Stop and get help today. |
Key exposure | Search your repository for service_role. Open the live site, look at the network tab, search the bundle for the same. | A service role key anywhere the browser can reach it bypasses every rule you've written. |
Policy content | In the Supabase dashboard, open a table's policies and read the USING clause. | USING (true) on a table with user data means every authenticated user can read every row. |
⚠ If the first test works, treat it as live and urgent. Anyone with an account can already read your users' data, and you will not see it in any log.
The process
How a rescue runs
Step | What happens | |
01 | Audit | We read the policies, keys, auth config and queries. Free, 48 hours. |
02 | Triage | Findings ranked by severity, with the exploitable ones separated from the untidy ones. |
03 | Harden | Policies rewritten to be correct, keys moved server-side, storage locked down. |
04 | Stabilise | Auth working across environments, edge functions reporting failures, constraints added. |
05 | Test | Access control tested from a second account, not assumed from the dashboard. |
06 | Handover | What was wrong, what changed, and how to keep it that way. |
Which builder was it?
The Supabase failures are similar across all of them; the route in differs.
Lovable · Bolt.new · Base44 · Replit · Cursor · v0 · Claude Code
You don't need a technical brief
What you have | What it tells us |
Supabase project access | The policies, keys and schema as they actually are |
GitHub repository | How the app queries the database — the other half of the answer |
Live URL | What's reachable without logging in |
The builder project | How it was wired in the first place |
Error messages | Where to start looking |
"Data isn't working" is a valid starting point. Working out which layer is broken is the audit's job.
Questions
Question | Answer |
Do you need access to my Supabase project? | Read access to the database and the repository covers most of it. We'll tell you if we need more, and why. |
My scanner said the app is fine. | Scanners check that RLS is enabled. They can't check whether a policy is correct or whether the app bypasses it with an elevated key. Those are the two most common causes of a leak. |
Will fixing RLS break my app? | It can, temporarily — that's why the feature was left open in the first place. We write the policies the app actually needs rather than turning protection off to make things work. |
Can you fix the data as well as the code? | Orphaned rows, duplicates and impossible states are repairable. We scope that separately once the audit shows how much there is. |
Firebase, Neon, PlanetScale, plain Postgres? | Same service. The failure classes are the same wherever access control is configured rather than written. |
I think we've already been breached. | Tell us immediately. That's a different and faster process, and the first hours matter. |
My app is live with real users right now. | Say so when you send the repository. Live exposure jumps the queue. |
Free audit
Send us the repository
You'll get the access-control gaps, the exposed secrets, the auth configuration problems and the schema risks — ranked, with the exploitable ones named first.
Read access is enough. Mutual NDA first if you'd prefer.
No charge. No obligation. Reply within 48 hours.
Also broken?
Authentication · Payments · Database and multi-tenancy · Security audit · Works in preview, breaks after deploy · Lovable · Bolt.new