VibeCPR

← Blog

Supabase · Survival guide

Check your Supabase RLS in two minutes (Lovable, Bolt, Cursor)

Published · VibeCPR

TL;DR Open your Supabase project → Security Advisor. If any table shows RLS disabled or a policy like 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

  1. Open Supabase Dashboard → your project.
  2. Go to Advisors → Security Advisor (sometimes under Database / Reports depending on the UI version).
  3. Look for warnings like:
    • RLS disabled on a public table
    • Policy always true / permissive policies
    • Tables exposed to anon without sensible policies

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:

CheckSafeDangerous
RLSENABLE ROW LEVEL SECURITYRLS off
Read policyScoped (e.g. auth.uid() = user_id, or intentional public read)No policy + grant to anon, or “open to world” by mistake
Write policyScoped to the owning user / roleUSING (true) / WITH CHECK (true) on insert/update/delete for anon
GrantsMinimal: anon only where logged-out visitors must readGRANT 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.

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.