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.