Rescue · Supabase security

Supabase RLS: Why Your AI-Built App Is Leaking Data

Row Level Security is the lock on every table in a Supabase app. AI builders routinely leave it off — because disabling it is the fastest way to make a demo work. Here’s the two-minute check, the real fix pattern, and what to do if you find a hole.

Severity: criticalFix effort: 1–2 daysCheck takes 2 minutes
Symptoms

Signs your RLS is broken

Tables say “RLS disabled”

Supabase → Database → Tables. Any user-data table showing that label is an open door — no attacker skill required, just your public anon key.

Policies that say USING (true)

A policy that allows every row to everyone isn’t a lock; it’s a doorstop painted to look like one. AI assistants generate these to silence permission errors.

The app never distinguishes users’ data

If every account seems to see the same lists, the queries may be unfiltered — which works only because nothing is enforcing boundaries.

Your service-role key appears client-side

That key bypasses RLS entirely by design. In the browser bundle it turns every other fix into theatre — rotate it first.

Your anon key is public by design

Every Supabase frontend ships its URL and anon key in the browser — that's normal and fine. RLS policies are the mechanism that stops a stranger using that key to read every row. No policies, no protection.

AI assistants optimise for ‘it works’

When a query fails with a permissions error mid-prompt, the fastest fix the model knows is disabling RLS or writing USING (true). The error disappears. The hole stays.

It fails silently

Nothing looks wrong. The app works perfectly for every user — including the one reading other people's rows with a curl command.

## The two-minute check
-- run in the Supabase SQL editor: which public tables have RLS off?
select tablename from pg_tables where schemaname='public' and rowsecurity=false;
-- and which policies allow everyone?
select tablename, policyname from pg_policies where qual='true';
# the outside view: can the anon key read a table it shouldn't?
curl "https://YOUR-PROJECT.supabase.co/rest/v1/profiles?select=*" -H "apikey: YOUR_ANON_KEY"

The fix pattern

01

Enable RLS Everywhere

Every table in the public schema, no exceptions. Tables that should be public get an explicit read-only policy — explicit beats accidental.

02

Write Policies From Product Rules

Users read their own rows (auth.uid() = user_id), admins via a role claim, shared data via join tables. The policy mirrors the product, not the error message.

03

Test as a Second User

Create a fresh account and try to read the first account's data — from the app and from curl. Passing your own access check proves nothing.

04

Move Privileged Work Server-Side

Anything that must bypass RLS — admin jobs, webhooks — runs with the service-role key inside an edge function. Never in the browser.

05

Assess the Exposure

Check API logs for unusual reads, rotate keys, and take an honest look at disclosure duties. Uncomfortable early beats catastrophic late.

FAQ

Common questions

How do I know if data was actually accessed?

Supabase logs API requests — look for table-wide reads from unfamiliar origins or volume spikes. Log retention on free plans is short, so check sooner rather than later; the triage includes this review.

Can I just ask Lovable to fix the policies?

It will produce plausible policies — but security is the one place plausible isn't enough. Policies must be derived from your product's rules and tested from a second account. This is worth a human.

Will enabling RLS break my app?

Parts of it, usually — the app was written assuming open tables. The real fix is policies plus the queries that respect them, tested together. Budget a day or two, not an hour.

Is the anon key itself the problem?

No — it's designed to be public. The problem is what the key can reach when no policies constrain it. Rotating the anon key without fixing RLS changes nothing.

What does a professional RLS fix cost?

Inside a rescue sprint it's part of the from-$2,499 fix. Standalone RLS-and-auth hardening on a small app is usually at the bottom of that range — the $299 triage quotes it exactly.

Keep reading

Related rescue guides

$299 triage · 48 hours · credited against any fix

Lock the database today

RLS review is the first item in every triage. In 48 hours you’ll know exactly what’s exposed and what it takes to lock it.

43+ happy clients · rated 4.9/5 · senior engineers on every build