How to Tell If Your Supabase Database Is Publicly Exposed
Here's the question that keeps Supabase users up at night: *if my anon key is in the browser where anyone can grab it, is my database public?* The honest answer is it depends entirely on your Row Level Security policies — and a lot of vibe-coded apps never set them up.
The anon key is not the lock — RLS is
Supabase hands every browser a public anon key. That key is supposed to be public; it only identifies your project. The thing that decides whether a request is allowed is Row Level Security (RLS): per-table rules that run on every query.
With RLS off (or on with no policies that grant access), the behavior depends on your setup — but the dangerous case is a table where RLS is disabled, which lets the public key read and write every row.
The 30-second self-check
Open your Supabase dashboard → Table Editor. For each table, look for the RLS status. If a table says RLS disabled, anyone with your anon key (which is everyone) can query it.
Then go to Authentication → Policies. A table with RLS *enabled* but zero policies denies all anon access — that's safe but may break your app. A table with a policy like `true` for `select` to `anon` is effectively public.
Test it like an attacker would
Grab your project URL and anon key (they're in your client code already) and hit the REST endpoint directly: `https://YOUR-PROJECT.supabase.co/rest/v1/your_table?select=*` with the `apikey` header. If rows come back for a table that should be private, it's exposed.
This is exactly the kind of check a passive scanner automates. Paste your app URL into Secure The Vibe and we'll flag Supabase usage and the configuration signals that suggest unprotected tables.
If you find an exposed table
Enable RLS on the table, then add policies that scope rows to the authenticated user — for example, `auth.uid() = user_id`. Never write a blanket `using (true)` policy for `anon` on a table with private data. Our deeper guide is Row Level Security, Explained.