VibeRaven

What does rls_disabled_in_public mean, and how do I fix it?

By Ohad Krispin, founder of VibeRaven · LinkedIn

rls_disabled_in_public is the Supabase Security Advisor error for a table the Data API exposes, usually in the public schema, that has row level security turned off. Supabase's lint docs say anyone with your project URL "can read, edit, and delete all data in this table". The fix is alter table ... enable row level security in a migration, then one policy for each read or write your app makes.

Terminal output of npx viberaven check on a Next.js + Supabase fixture: a migration table without row level security is a blocker, and after a migration enables RLS with a policy, the next run has none.

It is one of several Security Advisor warnings. For the others, see what each Supabase Security Advisor warning means.

How to fix rls_disabled_in_public, then check the fix

  • Enable row level security on the table the Advisor names. Put it in a new migration, not only in the SQL editor, so every environment gets it:
    alter table public.todos enable row level security;
  • Add a policy for each command your app runs on the table. With RLS on and no policy, Supabase's lint docs say you "will not be able to use the anon role to read or write data to the table", and signed-in users get nothing either, so the app stops working until you do. For rows that belong to one user:
    create policy "Users read their own todos"
    on public.todos for select
    to authenticated
    using ( (select auth.uid()) = user_id );
    
    create policy "Users add their own todos"
    on public.todos for insert
    to authenticated
    with check ( (select auth.uid()) = user_id );
  • Confirm RLS is on in the live project. relrowsecurity should be t:
    select relname, relrowsecurity
    from pg_class
    where oid = 'public.todos'::regclass;
  • Run the Security Advisor again, in the dashboard or from the Supabase CLI. The table should be gone from the list:
    supabase db advisors --linked --type security
  • Read the table as a signed-out visitor. On a Supabase Postgres 17.11 container on 20 October 2026, the anon role read another user's row from public.todos before the fix and 0 rows after it.

When rls_disabled_in_public is safe to ignore

When it fires, it is not a false positive. The lint's source flags a table only when RLS is off, the table is in a schema the Data API exposes, and anon or authenticated can select from it. These cases need a different fix, not no fix.

A table only your server reads

Enable RLS and add no policy. Your server uses the secret or service role key, which bypasses RLS, so it keeps working while browser requests get nothing.

A table the API should never reach

Revoke the browser roles' grants, all of them. The lint checks only SELECT: on the same container, revoking SELECT alone cleared the warning while the anon role could still insert rows. If you do not use the Data API at all, Supabase's lint docs also suggest removing the schema from Exposed schemas in the API settings.

revoke all on table public.todos from anon, authenticated;

Optional repo check

For AI-built Vercel + Supabase apps, an optional check, npx -y viberaven@1.6.8 check run from the repository root, finds this in migration SQL before it reaches the database. On a Next.js + Supabase fixture repo on 2026-10-20 it reported public.todos, created in a migration with no row level security, as rls_disabled, a blocker, with its file and line; after a second migration enabled RLS and added a select policy, the same command exited with code 0. It reads only the public schema in your migration files, not tables made in the dashboard or the grants your live project holds. It is advice, not a gate, and a repository check, not a live database or security test. It exits with code 1 when it finds a blocker and writes a .viberaven folder that it does not add to .gitignore.

Related guides

Sources

Why does the Advisor flag a table my app never calls?

The lint does not read your app code. It flags every table with RLS off in an exposed schema, public by default, that anon or authenticated can select from, because anyone can call that table directly at /rest/v1/ followed by its name. On the test container, a new table in public came with SELECT, INSERT, UPDATE and DELETE granted to anon.

Does enabling RLS delete or hide my data?

No. The rows stay, and the SQL editor and the secret or service role key still see all of them. Only requests made with the anon or publishable key, or a signed-in user's token, are limited to what your policies allow.