All guidesSupabase RLS and keys
On this page

Supabase Security Advisor

Supabase

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

By Ohad Krispin, founder of VibeRaven · LinkedIn

rls_enabled_no_policy is the Supabase Security Advisor notice, level INFO (lint 0008), for a table that has row level security turned on and no policies. Nothing is exposed: Supabase's lint docs say "no data can be read or written through the API", so the browser gets empty results while your server's secret or service role key still sees every row. The fix is one policy for each read or write your app makes, or, for a table only your server uses, a policy that says so on purpose.

psql output from a Supabase Postgres 17.11 container: lint 0008 flags public.todos and a signed-in user reads no rows. After a select policy, the lint returns nothing and the user reads their own todo.
psql output from a Supabase Postgres 17.11 container: lint 0008 flags public.todos and a signed-in user reads no rows. After a select policy, the lint returns nothing and the user reads their own todo.

Checklist

How to fix rls_enabled_no_policy, then check the fix

  1. 01
    Add a policy for each command your app runs on the table, in a migration. 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 );
  2. 02
    Confirm the policies exist in the live project, one row per policy:
    select policyname, cmd, roles
    from pg_policies
    where schemaname = 'public' and tablename = 'todos';
  3. 03
    Run the Advisor again. The CLI hides INFO findings unless you ask for them: on Supabase CLI 2.121.0, rls_enabled_no_policy showed only with --level info.
    supabase db advisors --linked --type security --level info
  4. 04Read the table as a signed-in user. On a Supabase Postgres 17.11 container on 22 October 2026, a signed-in user read 0 rows from public.todos before the select policy and their own row after it. With no insert policy, their insert failed with new row violates row-level security policy for table "todos".

Exceptions

When rls_enabled_no_policy is intended

The lint's source flags every table with RLS on and no policy, in any schema except system ones such as auth and storage. It does not check grants or whether the Data API exposes the schema.

A table only your server reads

This is the state you want: the secret or service role key bypasses RLS, and on the test container service_role read both rows while signed-in users read none. Supabase's lint docs suggest making the intent explicit with a policy that rejects everyone. On the container, it cleared the notice.

create policy "No API access"
on public.todos for select
using (false);

A table in a schema the API does not expose

A table in a private schema with RLS on and no policy is reported too: on the container, private.notes was. The Data API cannot reach it either way, so it is safe to leave.

Related

Sources

Official docs behind this checklist

FAQ

FAQ for builders before launch

Why does my Supabase query return an empty array with no error?

Row level security is on and no policy lets that role read the rows. Postgres filters the rows out instead of raising an error, so supabase-js returns an empty data array and no error. An insert does raise one: new row violates row-level security policy.

Is rls_enabled_no_policy a security problem?

No. It is the closed side of RLS, rated INFO. The open side is rls_disabled_in_public, an ERROR, for a table the API exposes with RLS off.