Skip to content
New New - every finding now ships with a copy-paste fix prompt for Cursor & Claude. See how
All posts
securityJun 10, 20267 min read

Supabase RLS: the default that leaks your whole database

Row-Level Security is off until you turn it on — and AI builders rarely do. Here is exactly how an attacker reads every row with nothing but your public anon key, and how to shut it.

When Lovable, Bolt or v0 wires your app to Supabase, it ships a public "anon" key in the browser bundle. That key is meant to be public — Supabase's security model assumes Row-Level Security (RLS) policies stand between the key and your data. The problem: RLS is disabled by default on every new table, and AI builders almost never enable it.

The result is the single most common flaw we find in vibe-coded apps: a fully public database sitting behind a key that is, by design, printed in your JavaScript.

How an attacker finds it in 30 seconds

There is no exploit kit required. The anon key and project URL are in your bundle, and the Supabase REST API is self-describing.

  • Open the deployed site and read the anon key + project URL straight out of the JS bundle.
  • Hit the auto-generated REST endpoint: GET https://<project>.supabase.co/rest/v1/<table>?select=* with the anon key.
  • If RLS is off, every row comes back. Users, orders, messages, API tokens — whatever the table holds.

Why "we added auth" does not save you

Front-end auth gates what the UI shows; it does nothing for a direct API call. The PostgREST endpoint Supabase exposes is reachable with the anon key regardless of whether your React app rendered a login screen. RLS is the only thing that scopes rows to the requesting user.

The fix

Enable RLS on every table, then write policies that scope rows to the authenticated user.

  • In the Supabase dashboard: Database → Tables → enable "Row Level Security" on each table.
  • Add a policy: create policy "own rows" on public.orders for select using (auth.uid() = user_id);
  • Verify from an anonymous client that the table now returns zero rows.
  • Re-scan: VibeSafely actually attempts the read and confirms it returns nothing, rather than just checking that a policy exists.

This is a one-time hardening that takes minutes — but only if you know to look. A free VibeSafely scan tells you in sixty seconds whether your anon key currently hands out rows.

See what your app left exposed.

One free scan, sixty seconds, no credit card — every finding with a copy-paste fix.

Scan my site — free