Fix.
Check whether your Supabase data is public in five minutes
Four checks you can run yourself, without a developer, to find out whether strangers can read your database.
Supabase gives every project a public API. That is the point of it: your app talks to your database directly from the browser. The only thing standing between a stranger and your data is row level security, and it is off by default for tables created any way other than through the Table Editor.
That means tables created by SQL, by a migration or by an AI builder often have no protection at all. Here is how to find out, without a developer.
Check 1: is RLS on at all?
In your Supabase dashboard, open the Table Editor and look down the list of tables. Any table showing a warning that RLS is disabled is readable by anyone who knows your project URL and your public key. Both of those are in your app’s JavaScript, visible to anyone who opens developer tools.
Turning it on immediately blocks all access until you add a policy, so do it on a table you can afford to break first, and expect that part of your app to stop working until the policy exists.
Check 2: do the policies actually check anything?
This is the one people miss. A table can have RLS on, a policy in place, and still be wide open, because the policy allows everything.
Open the policies for each table and read the condition. If it is true, or USING (true), that policy permits every request. It is the same as having no protection, with a reassuring green tick next to it.
A real policy compares something about the request to something about the row. The common shape is checking that the logged-in user’s id matches the row’s owner column.
Check 3: can a logged-out stranger read it?
The only test that counts. In a browser where you are not logged in to your app, open developer tools, go to the Console, and run a request to your own API using your public key. If data comes back, that data is public.
If you would rather not touch the console: log out of your app, open a private browsing window, and try to reach a page that shows data. Anything that still loads is not protected by the database.
Check 4: is your secret key in the browser?
Supabase gives you two kinds of key. The public one is meant to be in your app. The secret one, historically called the service role key, bypasses row level security completely. If it has ever been used in frontend code, nothing else on this list matters.
In your deployed site, open developer tools, go to Sources, and search the loaded files for service_role. Search your code for it too. If you find it anywhere in frontend code, rotate it in your Supabase dashboard today, then move whatever used it to a server function.
The four mistakes behind almost all of this
- RLS never turned on, because the table was not created in the Table Editor.
- A policy that allows everything, added to make the app work again.
- Access checked only in the browser, so hiding a button hides nothing.
- The secret key used in frontend code because it made an error go away.
After you fix it
Re-run check 3. A fix you have not tested from a logged-out browser is a fix you are assuming. That single test is worth more than reading every policy in the dashboard.
More articles on fix
- How to fix infinite recursion in Supabase RLSHow to resolve error 42P17 infinite recursion detected in policy for relation in Supabase when querying team or organization memberships.6 min read
- The vibe coded MVP audit checklistA practical 6-point checklist to find hidden security flaws, exposed secrets, and database performance traps in AI-generated web applications.8 min read
- Taking over a codebase someone else builtWhat to ask before you hand your project to someone new, and why a proper audit before any fix work protects you, not just them.6 min read
Have a project in mind?
Let's build it.
Whether you are building a new SaaS platform from scratch, launching a mobile product, designing a high-conversion interface, or need an urgent rescue for an AI-built app, we are ready to help. You will receive a clear scoped plan and milestone timeline within 1 to 2 business days.