Database | 12 of 20

RLS enabled is not RLS working

research, sourced

Row-level security is two things: a switch per table, and a policy per command. The switch alone blocks everything, which breaks the app, so the model adds a policy. The policy it adds is using (true), which allows everything. Green badge, every row readable. A view runs as its owner and bypasses RLS entirely unless security_invoker is on.

Where it bit

A June 2026 scan of 1,072 vibe-coded Supabase apps: 39 fully readable tables, 34 exposing emails, hashes or tokens, and 172 that allowed unauthenticated DELETE on tables named things like payments. A single Lovable education app: 18,000 users exposed.

The practice

One policy per command. Reads scoped to (select auth.uid()) = user_id. Inserts with with check. Roles from app_metadata or a roles table, never user_metadata, which the user edits from the browser. Read the Security Advisor before every deploy.

Check it

select tablename, rowsecurity from pg_tables where schemaname = 'public';
select tablename, policyname, cmd, qual from pg_policies where qual = 'true';   -- the lock that locks nothing
curl -s "https://PROJECT.supabase.co/rest/v1/users?select=*" -H "apikey: PUBLISHABLE_KEY"   -- should be []

Get this check as a script you can run tonight

Free, straight to your inbox. No call, no pitch

What to do with this

If you run a business on something AI built and the checks came back with more than you expected, that is worth a conversation.

We do a free 30-minute Health Check for service businesses that want to know exactly where their biggest leaks are. No slide deck. No pitch. We ask questions, find the gaps, and tell you what we see. If there is no obvious fix, we will tell you that too.

Blinkz finds what is broken in how a business runs, then fixes it. AI only where it earns its place.