Supabase security

Supabase RLS scanner

Your Supabase anon key is public by design. Row-Level Security is the only thing stopping someone who copies it from your site from reading, or rewriting, every row in your tables. VibeSafe scans your migrations and app code for the RLS mistakes AI builders ship, and explains each fix.

Scan your Supabase code free →

Paste your SQL migrations and the files that query Supabase · No signup to try

Why this matters more in AI-built apps

Lovable, Bolt and similar tools wire the browser straight to Supabase. That's fine when RLS is on and scoped correctly, and a data leak when it isn't. In our 400-app study, 35.2% of the repositories used Supabase, which makes RLS the single most important setting for a large share of vibe-coded apps.

The six RLS mistakes the scanner looks for

What a finding looks like, and the fix

A typical AI-generated migration:

create table notes (
  id uuid primary key default gen_random_uuid(),
  user_id uuid references auth.users not null,
  body text
);
-- no RLS: every row readable and writable with the anon key

The fix, scoped for every operation:

alter table notes enable row level security;

create policy "owner can read"   on notes for select using (auth.uid() = user_id);
create policy "owner can insert" on notes for insert with check (auth.uid() = user_id);
create policy "owner can update" on notes for update using (auth.uid() = user_id) with check (auth.uid() = user_id);
create policy "owner can delete" on notes for delete using (auth.uid() = user_id);

Check your live project by hand (2 minutes)

The scanner reads code; this confirms what your deployed database actually allows. Take the project URL and anon key from your site's network requests, then, on your own project only:

curl "https://YOUR-PROJECT.supabase.co/rest/v1/notes?select=*" \
  -H "apikey: YOUR_ANON_KEY" \
  -H "Authorization: Bearer YOUR_ANON_KEY"

If that returns other users' rows while logged out, RLS isn't protecting that table. An empty array [] is what you want. Repeat for each table that holds user data. The Supabase dashboard's security advisor also lists tables with RLS disabled.

What the scanner does not do

Questions

What does a Supabase RLS scanner check?

It looks for tables reachable from the browser without Row-Level Security, RLS enabled with policies that allow everyone, policies covering SELECT but not UPDATE or DELETE, INSERT and UPDATE policies without WITH CHECK, user filtering done only in app code, and a service_role key in client code that bypasses RLS entirely.

Can VibeSafe read my live Supabase policies?

No. VibeSafe scans code: your SQL migrations, schema files and the app code that queries Supabase. It does not log in to your database. Use the manual test on this page to confirm what your live project actually allows.

Is the Supabase anon key a security problem?

No. The anon or publishable key is designed to be public, which is exactly why RLS matters: anyone holding it can call your tables directly, and RLS limits what they get back. VibeSafe does not flag the anon key; it flags a service_role key in client code.

I enabled RLS and my app stopped returning data. Is that normal?

Yes. Enabling RLS denies everything until you add policies. Add a policy for each operation the app needs, scoped to the owner, for example auth.uid() = user_id.

An honest note. VibeSafe catches the common RLS mistakes quickly. For apps holding sensitive or regulated data, have a person review your policies as well.

Related: