Check your Supabase RLS in two minutes (Lovable, Bolt, Cursor)
Published · VibeCPR
USING (true) on writes, fix it before you ship. Your anon key is meant to be public; the tables behind it are not. Never “fix” access by granting everything to anon.Why this takes two minutes (and matters now)
Your Supabase anon (publishable) key is designed to sit in frontend code. That is fine only if every table has Row Level Security (RLS) on, with policies that actually restrict rows. If RLS is off—or a policy says USING (true) for writes—anyone who copies the anon key from your JavaScript bundle can read or change that table.
That pattern is common in vibe-coded apps. UpGuard reported 16,326 exposed Supabase databases in a scan published October 14, 2026. Separately, research tied to CVE-2025-48757 found inadequate RLS in 170 of 1,645 Lovable apps (about 10.3%). And on October 30, 2026, Supabase stops auto-exposing new public tables to the Data API on existing projects (changelog)—which makes grants + RLS + policies something you want to get right as one unit, not as a panic fix later.
Minute 1: Security Advisor
- Open Supabase Dashboard → your project.
- Go to Advisors → Security Advisor (sometimes under Database / Reports depending on the UI version).
- Look for warnings like:
- RLS disabled on a
publictable - Policy always true / permissive policies
- Tables exposed to
anonwithout sensible policies
- RLS disabled on a
If Advisor is clean, you are not done—but you have cleared the loudest alarms. If it flags tables, fix those first.
Minute 2: Spot the dangerous patterns yourself
In Authentication is not where policies live. Open Table Editor or SQL, then for each user-facing table ask:
| Check | Safe | Dangerous |
|---|---|---|
| RLS | ENABLE ROW LEVEL SECURITY | RLS off |
| Read policy | Scoped (e.g. auth.uid() = user_id, or intentional public read) | No policy + grant to anon, or “open to world” by mistake |
| Write policy | Scoped to the owning user / role | USING (true) / WITH CHECK (true) on insert/update/delete for anon |
| Grants | Minimal: anon only where logged-out visitors must read | GRANT ALL … TO anon as a “fix” |
The anon key myth
Seeing eyJ… or sb_publishable_… in your frontend is not automatically a leak. Supabase expects the publishable key in the browser. The leak is data: tables the anon role can reach because RLS is missing or policies are wide open. The service_role / secret key is different—that one must never ship to the browser. (See our leaked API keys guide.)
Never “fix” permission denied by opening the barn door
After Supabase’s Data API grant change, new tables can return 42501 permission denied until you add an explicit GRANT. The wrong fix is:
-- Do NOT do this
grant all on all tables in schema public to anon;
That can recreate the exact exposure Advisors and researchers keep finding. Treat grant + enable RLS + real policies as one migration. Details and safe SQL: Supabase October 30, 2026 guide.
Quick SQL you can run in the SQL editor
List tables in public without RLS:
select n.nspname as schema, c.relname as table_name
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where c.relkind = 'r'
and n.nspname = 'public'
and c.relrowsecurity = false
order by 1, 2;
Then for a flagged table:
alter table public.your_table enable row level security;
-- Example: users only see their own rows
create policy "users read own rows"
on public.your_table
for select
to authenticated
using (auth.uid() = user_id);
-- Avoid this for writes:
-- using (true) / with check (true)
Read every policy you (or your AI tool) creates. USING (true) on a select might be intentional for a public catalog; on insert/update/delete for anon it usually means “anyone can change anything.”
Copy-paste prompt for Cursor, Lovable or Bolt
Audit our Supabase public tables for exposure:
1. Enable RLS on every public table that the Data API touches.
2. List policies; rewrite any USING (true) / WITH CHECK (true) write policies
for anon or authenticated so they scope to auth.uid() (or an explicit,
intentional public-read select-only policy).
3. Do NOT grant all to anon. Grant anon only where logged-out users must read,
and only after RLS + policies exist in the same migration.
4. Show me the SQL diff before applying. Do not invent tables or columns.
After you fix it
- Re-run Security Advisor.
- Load your live app as a logged-out user and confirm public pages still work.
- If you granted new tables for the October 30 change, confirm you did not skip RLS.
- Join the free Vibe Check waitlist if you want a passive URL scan for leaked keys and headers once it launches—or a human-verified Rescue Report when you need repo + RLS review.
Related
- Supabase October 30, 2026: fix 42501 permission denied on new tables
- How to find and fix leaked API keys in a Lovable, Bolt or Cursor app
FAQ
Is my anon key leaked if it’s in the browser? No—that key is meant to be public. The risk is tables without proper RLS.
Security Advisor is green. Am I safe? It’s a strong signal, not a proof. Still review write policies and any GRANT to anon.
What’s the October 30 deadline again? Existing projects lose auto-exposure of new public tables to the Data API on that date; existing tables keep their grants. See the changelog and our patch notes post.
Get Patch Notes
One email a week: breaking changes and security fixes for apps built with AI. Also puts you on the waitlist for the free Vibe Check.