← Supabase RLS exposure checker

Why disabling RLS exposes your Supabase data

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.

What happens when RLS is off

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.

This is not hypothetical -- CVE-2025-48757

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.

Why this stays easy to reintroduce

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.

Check your own project

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.

← Back to the Supabase RLS exposure checker