Use case
Supabase RLS Check
Row Level Security is the most important Supabase setting most AI-built apps get wrong. When RLS is disabled, every table is readable by any visitor with the anon key — and the anon key is almost always in the client bundle. The free scan looks for a leaked service role key; Deep Scan checks, read-only and only on a site you have verified you own, whether your tables return rows to the anon key.
What Row Level Security does and why it matters
- RLS (Row Level Security) is a PostgreSQL feature that controls which rows a query can return based on the user making the request.
- When RLS is enabled on a table, a SELECT without a matching policy returns zero rows — even with the anon key.
- When RLS is disabled, any authenticated or anonymous Supabase client can read every row in that table.
- Supabase enables RLS by default on new tables in recent dashboard versions, but older tables and tables created via migrations may have it disabled.
The common failure pattern
Lovable, Bolt, and v0 generate Supabase code quickly. The generated code often uses the anon key for client-side queries without confirming RLS is enabled. The resulting app appears to work correctly because the developer is authenticated and sees their own data — but unauthenticated visitors can also read every row.
What GetLeaked checks
Four checks, and which scan runs them.
01
Service role key exposure (free scan)
The Supabase service role key bypasses all RLS policies entirely. If it appears in your page, a client bundle or a declared source map, any visitor can read and write every table. The free scan decodes each candidate token and only reports it when the payload really says role service_role.
02
Anon key and project reference (Deep Scan)
The anon key is designed to be public, but it becomes a data access key on any table without RLS. Deep Scan reports the Supabase project reference and the anon key it finds in your bundle, redacted, so you know which project to review.
03
Table and storage read check with the anon key (Deep Scan, owner-verified)
When your bundle exposes a Supabase URL and an anon key whose token names that same project, Deep Scan lists the tables the anon key can see and counts the rows each of up to 20 of them returns, using a HEAD request so no row is ever transferred. It also lists the storage buckets the anon key can see and whether each is public. It keeps only names, HTTP status and counts, never row contents or the key, and it runs only on a site you verified you own in the last 24 hours. It is opt-in per project, because a page can embed another app's Supabase keys: the report gives you a short SQL snippet to run in that project, which creates public.getleaked_ownership_proof(), a function that returns a token issued for you and reads no data. Before anything else, Deep Scan makes one read-only call to that function. Only an exact match unlocks the check, for that project only; otherwise nothing else is sent to Supabase and you get the snippet and a drop-function cleanup line. A table that gives no usable answer (a throttled request, a server error, a timeout) is reported as inconclusive, never as safe.
04
A SQL fix for every gap (Deep Scan)
Each readable table comes with SQL that first lists the table's policies, then drops or replaces any permissive anon or public read policy (such as using (true)), keeps Row Level Security on, can revoke the anon grant, and adds an example owner policy using auth.uid(). Adding a policy alone does not close a permissive one, so policy review is required. Each listed bucket comes with an example storage.objects policy, and a public bucket with the statement to make it private.
Scope and limitations
GetLeaked tests what the public anon key can read. For a full policy review, check the Supabase dashboard.
- The free scan does not contact your Supabase project; it only looks for the service role key on your public surface.
- The Deep Scan read check only uses the anon key your own app ships, only sends GET and HEAD requests, and checks at most 20 tables and 20 buckets. It does not list files inside buckets (Supabase only offers that as a POST), and it does not test writes or logged-in users.
- A table that returns no rows to the anon key may still have a policy that is too broad for logged-in users. Review your policies in the Supabase dashboard as well.
Verify your Supabase app before users find the gap.
Paste your public URL for a free check for a leaked service role key. Deep Scan adds the owner-verified anon-key table and storage read check, with SQL fixes.