Home / Errors / Supabase / rls-off

Supabase Row Level Security is off: your whole database is readable with the anon key

Supabase Moderate 30-90 minutes security critical Last verified Jul 17, 2026
The fix  This is an active breach risk, not a warning to snooze. Your anon key ships in the JS bundle by design; with RLS off it works like an admin key. Run `ALTER TABLE public.your_table ENABLE ROW LEVEL SECURITY;` on every exposed table, then add explicit policies per operation. Enabling RLS with no policies blocks all anon access, which is the safe direction to break.

Symptoms

  • The Supabase dashboard shows 'RLS disabled' warnings you may never have looked at
  • Anyone who copies the Supabase URL and anon key out of your app's JavaScript (both are always visible in the bundle) can read, modify, or delete every row through the auto-generated REST API, no login needed
  • The Security Advisor lists tables with RLS disabled
  • Your app was generated by an AI builder and you never wrote a single policy

Why it happens

AI codegen skipped RLS entirely

The AI ran CREATE TABLE statements without `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` and without any policies. The tables work, the app works, and the database is wide open.

The anon key is public by design

Supabase's anon key is meant to be shipped to browsers. It is only safe when RLS restricts which rows each request can touch. With RLS off, the anon key is effectively an admin key.

The CVE-2025-48757 pattern

This exact failure exposed 170+ production Lovable-built apps, and it sat behind Moltbook's leak of roughly 1.5 million API tokens and tens of thousands of emails. Research on the Lovable disclosure found about 10% of analyzed apps with RLS bypassed. Lovable patched its generation pipeline, but every app generated before the fix stayed vulnerable until its owner enabled RLS manually.

The service_role variant

A related failure is shipping the service_role key in client code. That key bypasses RLS entirely, so enabling RLS does nothing against it.

How to fix it

  1. List every exposed table (do this now, your data is publicly readable until RLS is on)In the Supabase dashboard, open Advisors / Security Advisor, or scan the Table Editor, and list every table with RLS disabled. Each one is fully readable and writable with the anon key from your bundle.
  2. Enable RLS on each tableRun `ALTER TABLE public.your_table ENABLE ROW LEVEL SECURITY;` for each exposed table. Enabling RLS with zero policies blocks all anon access, so parts of your app will break until you add policies. That is the safe direction to break in.
  3. Write explicit policies per operationFor example: `CREATE POLICY "own rows" ON public.profiles FOR SELECT USING ((SELECT auth.uid()) = user_id);` and write equivalents for INSERT, UPDATE, and DELETE. Each operation gets its own deliberate policy.
  4. Check for a leaked service_role keySearch your frontend bundle for the service_role key. If it ever shipped client-side, rotate it in Project Settings > API immediately. RLS does not protect against service_role.
  5. Verify from the outsideWith no auth, run `curl 'https://<project>.supabase.co/rest/v1/<table>?select=*' -H 'apikey: <anon-key>'` and confirm you get only the rows an anonymous user should see, which is usually none.

How to prevent it

  • Enable RLS the moment a table is created; make it part of every CREATE TABLE the AI runs.
  • Check the Security Advisor after every AI-driven schema change.
  • Keep the service_role key server-side only, forever.
  • Re-run the anonymous curl test against your tables after each schema migration.

Tools that actually fix this

Recommended because they address the failure mode above, not because of the payout. Some are affiliate links; see how we choose.

Frequently asked questions

Is the Supabase anon key safe to expose in my frontend?

The Supabase anon key is designed to be public, but only when Row Level Security is enabled with policies on every table. With RLS off, the anon key works like an admin key: anyone who copies it from your bundle can read, modify, or delete every row through the auto-generated REST API. Enable RLS and write per-operation policies before treating the anon key as safe.

What is CVE-2025-48757?

CVE-2025-48757 is the vulnerability pattern where Lovable-built apps shipped with Supabase Row Level Security disabled or bypassed, leaving their databases readable and writable with just the public anon key. It exposed 170+ production apps, and research found roughly 10% of analyzed apps affected. Lovable patched its generation pipeline, but apps generated before the fix stayed vulnerable until owners enabled RLS manually.

Will enabling RLS break my app?

Probably, and that is by design. Enabling RLS with zero policies blocks all anonymous access, so queries your app relied on will start returning nothing until you add explicit policies for SELECT, INSERT, UPDATE, and DELETE. Breaking closed is the safe direction: better a broken feature than a public database.

What if the service_role key was in my client code?

Rotate it immediately in Project Settings > API. The service_role key bypasses Row Level Security entirely, so enabling RLS does nothing against it. Treat any service_role key that ever shipped in a bundle as compromised, and use it only in server-side code afterward.

Sources

Related errors

The Vibe Oops briefing

One email when something ships to production that should not have. New incidents, new error guides, no filler.