Skip to content

Is your AI-built app leaking data? A 10-minute Supabase check

Apps built with Lovable or Bolt on Supabase often go live with tables anyone can read. How to check yours in ten minutes, and what to fix first.

3 min read

Apps built with Lovable, Bolt or similar tools usually store their data in Supabase. That is a good choice: Supabase is a real Postgres database with authentication built in. But it comes with one rule that AI tools don’t always follow, and when they miss it, the app’s data can be read by anyone who opens the browser’s developer tools.

This guide shows how to check your own app in about ten minutes, without installing anything.

Why the key in your app is public

Your app talks to Supabase from the browser, so the browser needs a key. That key, called the anon key (or publishable key in newer projects), is shipped inside your app’s JavaScript. Anyone can find it. This is by design.

What protects your data is not the key but Row Level Security (RLS): rules in the database that decide which rows each visitor may read or change. With RLS on and good rules, a public key is harmless. With RLS off, the public key reads the whole table.

Situation What a stranger with your public key can do
RLS off on a table Read (and often change) every row
RLS on, no rules Nothing: every request is refused
RLS on, rule using (true) The same as RLS off, for the actions and roles the rule covers
RLS on, rule tied to auth.uid() Only rows that belong to the signed-in user

Step 1: list tables without RLS

Open your project in the Supabase dashboard, go to the SQL Editor and run:

Tables in the public schema and their RLS status
select c.relname as table_name,
       c.relrowsecurity as rls_enabled
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public'
  and c.relkind = 'r'
order by c.relrowsecurity, c.relname;

Every row with rls_enabled = false is a table the public key can reach. Tables created in the Table Editor get RLS by default; tables created by SQL, which is how most AI tools create them, do not.

The dashboard’s Security Advisor flags the same problem as RLS Disabled in Public. If it shows any errors, start there.

Step 2: look for rules that allow everything

RLS that is on but too generous is just as open. List your rules:

Every RLS policy in the public schema
select tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'public'
order by tablename, cmd;

Look closely at rules where qual or with_check is simply true, especially for the anon or public roles. A rule like that on a profiles or orders table means anyone can read every profile or every order.

Step 3: confirm from the outside

Now test it the way an attacker would: with only the public key. Find your project URL and key under Project Settings → API, then run:

Read a table with the public key
curl "https://YOUR-PROJECT.supabase.co/rest/v1/profiles?select=*&limit=5" \
  -H "apikey: YOUR_PUBLIC_KEY"

How to read the answer:

  • Rows that are not yours: the table is exposed. Fix it today.
  • An empty list []: either the table is empty or RLS is filtering everything out, which is what you want.
  • A permission error: the table is not reachable through the API at all. Also good.

Repeat for every table that holds personal data, payments or anything private.

Step 4: make sure the secret key is not in your app

Supabase also gives you a service role key (or secret key, starting with sb_secret_). It ignores RLS completely and must only ever live on a server. Open your live app, press F12, go to Sources and search the JavaScript for service_role and sb_secret_. If either appears, rotate the key in the dashboard immediately and move the code that needed it to a server function.

What to fix first

  1. Rotate any secret key that reached the browser.
  2. Enable RLS on every table in the public schema: alter table public.profiles enable row level security;
  3. Replace using (true) rules on private tables with rules tied to the signed-in user.
  4. Run Step 3 again and confirm that a stranger gets nothing.

Turning RLS on will break any screen that relied on the open table. That is expected: each screen now needs a rule that allows exactly what it should. If your app was generated by AI and you are not sure which rules it needs, that is the work our Security Check starts with.

SupabaseLovableRow Level SecurityAI-built apps

This article is also available in: PortuguêsEspañol日本語中文

All articles