Can anyone read your Supabase tables with the public anon key?
This check reads Supabase tables your site code names, using the public anon key your site already ships, and flags any that return rows. It asks for at most one row and keeps no values.
What does this check look at?
It looks at whether a Supabase table your site code names returns rows to a read with the public anon key. Table names come from your own site code, never from guessing.
Supabase says a table in an exposed schema without RLS is readable and writable by any role with a grant on it. It also says a read policy for anon that is always true grants every unauthenticated visitor read access, and should be used only for data meant to be public.
Only a Deep scan runs it, after you prove you own the site. It applies only when the site code talks to Supabase.
What does a result mean?
| What the report shows | What it means | What to do |
|---|---|---|
| High finding | A table returned rows to the anon key. | Turn on row-level security with policies that fit your users, then read again. |
Rows returned to the anon key do not prove row-level security is off, because a deliberate public read policy gives the same answer. The anon key is not a secret, so the fix is the table rules, not hiding the key. A clean result means nothing was found in what the scan read. It does not prove the problem is absent from parts the scan never sees.
How serious is a finding?
Fix this first when it is confirmed. Anyone could use a finding of this kind on their own, with no victim and no second step. Confidence starts high, because a response from your site shows the thing itself. The report lists what to fix by how directly someone could use it, not by the severity label. These come up often with apps built quickly on services like Supabase or Firebase, where access rules start open while you build and are easy to forget.
What does a confirmed finding have to show?
| Part | For this check |
|---|---|
| Where it starts | The anon key the client bundle ships by design |
| The protection that should stop it | Row-level security did not stop an anonymous read |
| What is reached | An unauthenticated select returned rows |
| What follows | At least one table row is readable by anyone |
Fix it with your AI
Turn on row-level security for the table, write policies for who may read what, and test with the anon key again.
In my Supabase project, this table returns rows to the public anon key: [paste the table from the report]. Enable row-level security on it. Write select policies so signed-in users only see their own rows (for example using auth.uid() = user_id), and keep a policy for anon only if some rows are meant to be public. Revoke anon grants the table does not need. Then show me how to repeat an anon read and confirm it returns nothing private.How to check
Say Atlas, our example app at atlas.example, created a profiles table during a weekend build and never turned row-level security on. A Deep scan reads one row with the anon key and flags it.
Deep scans come with the Deep plan, and pricing shows what it includes. Pulse or Deep explains what each scan reads, and the full list of checks shows the rest.
Questions people ask
Does this prove row-level security is off?
No. A deliberate public read policy returns the same rows. The finding says anyone can read the table. Whether that is intended is your call.
Should I hide my anon key?
No. It is built to be public. The table rules decide what it can reach.
Run this check on your site
Only a Deep scan runs this check, once you prove you own the site. Deep walks your whole site, the scripts it loads and your API surface.
Run a Deep scanSources
- How we rate findings Lockpick docs, read on October 7, 2026
- Row Level Security Supabase docs, read on October 7, 2026
- Your admin page is online Lockpick docs, read on October 7, 2026