Supabase RLS checker: can anyone read your tables?
Your app's public key is in its code for anyone to copy. Row-level security decides what that key can read. Enter your project, the key and your table names, and see which tables hand their rows to someone who never signed in.
Your browser asks Supabase directly. Nothing goes through Refinar, and no row is downloaded.
What each result means
One read-only request per table, asking for zero rows and the count. No row values leave your project.
- Anyone can read
- Rows came back with only the public key. RLS is off on the table, or a policy lets the anon role read it. Fix these first.
- No rows visible
- Nothing came back. A policy is hiding the rows, or the table is empty — an empty table can't show which.
- Blocked
- The public role has no permission on the table at all, so the key can't read it whatever the policies say.
- Not found
- The API doesn't serve a table by that name: a typo, a table in another schema, or a schema that isn't exposed.
See every table and its RLS setting
The checker only knows the names you give it. This query, run in your own dashboard, lists them all.
Every table in public, with RLS and its policy count
select c.relname as table_name,
c.relrowsecurity as rls_enabled,
count(p.policyname) as policies
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
left join pg_policies p
on p.schemaname = n.nspname and p.tablename = c.relname
where n.nspname = 'public' and c.relkind in ('r', 'p')
group by c.relname, c.relrowsecurity
order by c.relrowsecurity, c.relname;Run it in your project's SQL editor. A table where rls_enabled is false can be read with the public key unless its access was revoked, and one with RLS on but no policies is closed to it. Paste the names into the checker to confirm.
What it doesn't check
- Reading only. It never tries a write, so it can't tell you whether anyone can insert, change or delete rows. The query below shows how many policies each table has; check the write ones.
- Only the tables you name, up to 25 at a time. A public key can no longer list a project's tables, so the query below is how you find the ones you forgot.
- Only what a visitor who isn't signed in can see. A policy that lets every signed-in user read every row will look closed here and still be open to anyone who makes an account.
- The public schema, through the REST API. Storage buckets, edge functions and database functions called with rpc() aren't checked.
Supabase RLS questions
Not sure which key you have? Check whether it's safe to expose or see which variables reach the browser.
What is row-level security in Supabase?
A Postgres feature that decides, row by row, what each role may read or change. Supabase's public key runs as the anon role, or as authenticated once someone signs in, so your RLS policies are the only thing between that key and your data. With RLS off on a table in the public schema, the public key can read every row of it.
How does this checker work?
For each table you name, your browser sends one GET request to your project's API with your public key, asking for zero rows and the total count. If the count is above zero, anyone with your key, which is in your app's code, can read those rows. Nothing is written, no row values are downloaded, and nothing goes through Refinar.
Why do I have to type my table names?
Supabase stopped letting public keys read the API schema in 2026, so a public key can no longer list a project's tables. You know your tables, and the SQL query on this page lists every one with its RLS setting and policy count when you run it in your own dashboard.
A table says no rows visible. Is it safe?
Probably, but the check can't prove it. Zero rows means either a policy is hiding them or the table is empty, and an empty table looks the same either way. Check it again once it has data, or confirm in the dashboard that RLS is on.
Why won't it take my service_role or secret key?
Those keys bypass row-level security, so a check made with one says nothing about what visitors can reach. And a secret key typed into any web page should be treated as leaked. If yours has been anywhere public, rotate it in Settings > API Keys.
How do I fix a table anyone can read?
Run alter table ... enable row level security in the SQL editor, or switch RLS on for the table in the Table Editor. With RLS on and no policies, the public key can read nothing, so then add a policy for who should see what, usually rows where auth.uid() matches the row's owner.
Does it check inserts, updates and deletes?
No. Testing a write policy means trying a write, and this page never does. Run the query on this page to see which tables have RLS on and how many policies each has, and open the Security Advisor in your dashboard, which flags tables in the public schema with RLS off.
Why did my AI-built app end up with RLS off?
Tables made in the Table Editor have RLS on by default, but tables created by SQL or a migration don't unless the script switches it on. Builders and agents that write migrations sometimes skip that step, or switch RLS off to make an error go away.
What about views?
A view runs with its owner's permissions by default and can return rows from a table that has RLS on. If a view in your public schema shows up as readable, recreate it with security_invoker = true so it respects the caller's policies.
Other free tools
- Broken-app checkWhy is my app broken?
- Error lookupWhat does this error mean?
- Key checkerIs this key safe to expose?
- AGENTS.md generatorWhat should my AGENTS.md say?
- Variable checkerWhich variables reach the browser?
- Landing page analyzerWhy isn't this page converting?
- PRD generatorWhat exactly should we build?
- Launch checklistIs this site ready to launch?
- Pull request explainerWhat does this pull request actually change?