Row level security not enabled
No rules at all. With API access granted, anyone with the public key can read and change every row.
- Severity
- Critical (high without personal data)
- Who can exploit it
- Anyone on the internet
- Found by
- Free RLS check (static) and the full lab check
- Lab proof
- Automatic: anon, stranger and owner reads
What it is
Without RLS, a table has no row-level rules. If the API roles (anon, authenticated) have been granted access to it, anyone holding your public key can read, insert, change and delete every row through the Supabase API. The free RLS check rates it critical when the table has personal columns, high otherwise.
Supabase changed its defaults in 2026: new tables in public are no longer exposed to the API automatically (the default for new projects from 30 May, enforced on all projects from 30 Oct 2026, with existing grants kept). Older tables, and any migration that grants access explicitly, are still exposed.
Of the 70 rebuilt apps (22% of 318) where anyone with the public key could read personal data, this pattern and PL-001 were the two routes (PatchLabs lab study, n=318, Nov 2026).
Example of vulnerable code
Simplified from the patterns we see in AI-built apps. Synthetic: not taken from any real app.
create table public.leads (
id bigint generated always as identity primary key,
name text,
email text,
phone text,
created_at timestamptz default now()
);
-- No "alter table public.leads enable row level security;"
grant all on public.leads to anon, authenticated;
Check it yourself
-- 1. Tables in public with RLS switched off
select c.relname as table_name
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public' and c.relkind = 'r' and not c.relrowsecurity;
-- 2. Can the API roles reach them?
select table_name, grantee, string_agg(privilege_type, ', ') as privileges
from information_schema.role_table_grants
where table_schema = 'public' and grantee in ('anon', 'authenticated')
group by table_name, grantee
order by table_name;
The fix PatchLabs writes
PatchLabs switches RLS on and adds back exactly what the app uses. Here the public contact form keeps working and only admins can read the leads.
alter table public.leads enable row level security;
-- The contact form can still submit
create policy "Anyone can submit a lead"
on public.leads for insert
to anon, authenticated
with check (true);
-- Only admins can read them
create policy "Admins read leads"
on public.leads for select
to authenticated
using (exists (
select 1 from public.user_roles r
where r.user_id = (select auth.uid()) and r.role = 'admin'
));
Every fix arrives as a migration file (plus any code change it needs, noted in the report) for your engineer to approve. Download it, or commit it on GitHub in one click from the report page. Automatic pull requests need our GitHub App, which is coming.
The proof it runs
[BEFORE] anon → 3 rows LEAK email •••••@••••• phone +•• •••• [FIX] enable RLS + scoped policies [PROVE] anon → 0 rows DENIED stranger → 0 rows DENIED admin → 3 rows OK [DONE] lab proof passed
Here the "owner" is the admin who is meant to read the leads; the proof checks that the right person keeps access, not just that everyone else is locked out. The lab rebuilds with Supabase's default grants, so it sees the same exposure the live API would.
When the pattern is intended
Strictly, a table with RLS off is safe if the API roles have no grants on it, for example a table only server code uses. Switch RLS on anyway: it costs nothing, and it keeps the table closed if someone adds a grant later. If you must leave it off, the report notes the reason and stops alerting once you confirm.
Supabase linter
- 0013 rls_disabled_in_public
- Flags tables in
publicwithout RLS. It reports an error level. - 0007 policy_exists_rls_disabled
- Flags tables that have policies written but RLS switched off, so the policies do nothing.
Related findings
Anonymous visitor can read personal data
Anyone with your app's public key can read emails, phone numbers or addresses.
PL-003RLS enabled but no policies (owner locked out)
Not a leak, yet. The table is locked to everyone, and the quick fix people reach for is the leak.
PL-005Always-true policy
A policy that says yes to everyone. On writes, anyone can change or delete your data.
Guides
- Supabase RLS policies explained, with owner and stranger tests
- How to secure a Lovable app’s Supabase database
- Pre-launch security checklist for vibe-coded apps
Free check
Does your app have PL-008?
Paste your public repo. We rebuild the database from your migrations, test it as a visitor, a stranger and the owner, and hand you the proven fix.
Last reviewed 10 Nov 2026. Finding IDs are stable: link to them freely. Spotted a mistake? Tell us.