← Supabase RLS exposure checker
Supabase's REST API (PostgREST) is designed to be called directly from a browser tab -- that is
the whole point of the anon key: it is meant to sit in your app's public
JavaScript bundle, the same as a Firebase web config or a Stripe publishable key. What keeps that
safe is not the key being secret. It is Row Level Security (RLS), a PostgreSQL
feature that restricts which rows a query is allowed to touch, and Supabase's own model puts the
entire enforcement burden on it: the anon role already has a schema-level USAGE
grant the moment a table exists, so the only thing standing between the public key and every row
in that table is whether RLS is turned on and a policy actually restricts it.
A table with RLS disabled behaves, over the REST API, as if any policy allowed everything: a
plain unauthenticated GET to /rest/v1/<table> with only the anon
key returns every row. Not a subset scoped to "your own" anything -- every row, to every visitor,
including one who never logged in. The same is true for POST/PATCH/
DELETE if the anon role also has the corresponding grant, which is Supabase's
default for a freshly created table.
In 2025, security researchers found this exact pattern across applications built with AI app-builder platforms, most widely reported for Lovable: generated Supabase tables were left without RLS enabled, and 170+ applications and 303+ endpoints turned out to be readable (and in some cases writable) by anyone with the project's public anon key -- which, again, is not a secret an attacker needs to steal, because it is already in the page source. A 2025 analysis of AI-generated apps found roughly one in ten tested applications exposed a vulnerable Supabase endpoint this way. Reporting into 2026 continued to find fresh instances, including at least one case where an AI platform's own database was exfiltrated after an attacker found a table with RLS missing and pulled admin emails and internal schema metadata out of it.
Supabase improved its defaults in 2026 -- new tables get RLS enabled by default in current projects, and the dashboard now flags and emails project owners about tables that lack it. That closes the gap for a brand-new project, not for one created before the change, and not for the ordinary case where RLS is enabled correctly on 30 tables and the 31st, added in a migration six months later, is not. The dashboard's own Security Advisor lint catches this too -- but only for someone logged in as a project member looking at it, which is exactly the moment a live check from the outside, using only the key any visitor's browser already has, earns its keep.
A free tool that runs exactly the check above -- reads your project's schema listing, requests one row from each table it finds, and names which ones return real rows to an unauthenticated request -- is at the Supabase RLS exposure checker. It runs entirely in your browser (or as a CLI for CI), and never sends your project URL, key, or anything it reads back to any server of ours. As with any tool that sends requests to a project you name, only run it against one you own or are authorised to test.