All guidesSupabase RLS and keys
On this page

Supabase Security Advisor

Supabase

What does permissive_rls_policy (rls_policy_always_true) mean, and how do I fix it?

By Ohad Krispin, founder of VibeRaven · LinkedIn

permissive_rls_policy is the Supabase Security Advisor warning (lint 0024, level WARN) for a row level security policy whose condition is always true, such as with check (true) on insert or using (true) on update or delete. The Advisor reports it under the name rls_policy_always_true. RLS is on, but that policy lets every role it names write or change any row. The fix is to replace true with a condition on the caller, such as (select auth.uid()) = user_id.

psql output from a Supabase Postgres 17.11 container: lint 0024 flags an insert policy with check (true), and a signed-in user adds a row owned by someone else. After the fix, the lint returns nothing and the insert fails.
psql output from a Supabase Postgres 17.11 container: lint 0024 flags an insert policy with check (true), and a signed-in user adds a row owned by someone else. After the fix, the lint returns nothing and the insert fails.

Checklist

How to fix permissive_rls_policy, then check the fix

  1. 01
    Find the policy. The Advisor's detail names the table, the policy and the command. This lists every policy in public whose condition is exactly true:
    select tablename, policyname, cmd, roles, qual, with_check
    from pg_policies
    where schemaname = 'public'
      and (qual = 'true' or with_check = 'true');
  2. 02
    Replace it with a condition on the caller, in a migration. For an insert policy:
    drop policy "Signed-in users can add todos" on public.todos;
    
    create policy "Users add their own todos"
    on public.todos for insert
    to authenticated
    with check ( (select auth.uid()) = user_id );
  3. 03
    An update policy needs both clauses: using picks the rows a user may change, and with check limits the values they may write, so a user cannot hand a row to someone else:
    create policy "Users update their own todos"
    on public.todos for update
    to authenticated
    using ( (select auth.uid()) = user_id )
    with check ( (select auth.uid()) = user_id );
  4. 04
    Run the Advisor again. The policy should be gone from the list:
    supabase db advisors --linked --type security
  5. 05Try the write as another user. On a Supabase Postgres 17.11 container on 22 October 2026, a signed-in user inserted a row owned by someone else before the fix; after it, the same insert failed with new row violates row-level security policy for table "todos".

Exceptions

When rls_policy_always_true is intended, and what it misses

The lint's source flags only permissive policies, only for anon, authenticated or a policy with no TO clause, and only on tables with RLS on.

A table anyone may write to on purpose

A waitlist or contact form may take inserts from anyone. Keep with check (true) on insert, give no select policy, and write down why: Supabase says some findings may be intentional. The Advisor keeps listing it.

Read policies with using (true)

Supabase's lint docs list using (true) among the patterns, but the lint's source skips select policies, because public reads are often deliberate. On the container, a select policy with using (true) for anon and authenticated was not flagged. So a table that leaks through a read policy does not show up here; check those yourself.

Go deeper: What does using (true) mean in a Supabase RLS policy, and when is it wrong?

Related

Sources

Official docs behind this checklist

FAQ

FAQ for builders before launch

Why are there two names for this warning?

Supabase's lint docs file it as 0024_permissive_rls_policy, while the lint itself reports the name rls_policy_always_true, with the title RLS Policy Always True. supabase db advisors printed that name on Supabase CLI 2.121.0. Both mean the same check.

Is a restrictive policy with true flagged?

No. A restrictive policy can only narrow what permissive policies allow, so a true one changes nothing, and the lint skips it.