If you built your app with Lovable, Bolt, or another AI tool that uses Supabase, there's a good chance your database is reachable directly from the browser. That's how Supabase is designed, and it's a big part of why these tools can build a working app in an afternoon.
It also means one setting carries most of your app's security. It's called Row Level Security, RLS for short, and when it's missing or wrong, anyone who opens your site can read your data. It's behind the Moltbook leak and the 170 exposed Lovable apps.
This guide explains it without SQL.
Why your database key is in the browser
A traditional web app has three layers: the page in your browser, a server in the middle, and the database behind it. The page never talks to the database. It asks the server, and the server decides what to hand back.
Supabase lets you skip the middle layer. Your page talks to the database directly, using a key that ships inside the page's code. Anyone can see it. Open your site, press F12, go to the Network tab and you'll find it in the requests to supabase.co, labelled apikey.
That's fine, and Supabase says so: the public key (called the anon or publishable key) is safe to expose as long as RLS is enabled. With the server removed from the picture, something else has to decide who gets what, and RLS is that something.
What RLS actually does
RLS is a list of rules attached to each table. Before the database returns or changes any row, it checks the rules against whoever is asking.
In plain English, good rules sound like this:
- A user can read their own profile.
- A user can read orders where they are the customer.
- Anyone can read published blog posts. Nobody can read drafts.
- Nobody can read the table of API tokens from the browser at all.
When a request arrives with the public key, the database knows who's signed in (or that nobody is) and filters every row through those rules. A user asking for "all orders" gets only their own. A stranger asking for "all users" gets nothing.
Without RLS, the database has no rules to apply, so it answers every question.
Where it goes wrong
RLS is off on a table
This is the Moltbook case. Often it's a table added later ("let's store invoices too") where the AI created the table and the feature but not the rules. Supabase now warns about this in the dashboard, and so do tools like Lovable's security scan.
The rule says yes to everyone
A policy whose condition is simply true is the same as no rule. AI tools sometimes write this when a feature isn't working and the quickest fix is to open the door.
The rule only checks that someone is logged in
This is the sneaky one. It passes every "is RLS enabled?" scan, and it still means any customer can read every other customer's rows. For a B2B app, that's one client seeing another client's data.
The secret key in the browser
This one sits outside RLS entirely. Supabase gives you a second, secret key that ignores all rules, meant for servers only. If an AI tool ever put it in your frontend code to "fix a permissions error", every rule you wrote is irrelevant. Search your code for service_role and for the SUPABASE_SERVICE_ROLE_KEY variable name. It must never appear in anything that runs in the browser.
Check yours in 15 minutes
Step 1: look (5 minutes)
In the Supabase dashboard, go through every table in the public schema. Each should say RLS is enabled. Click into the policies and read them. For each table, you should be able to say in one sentence who can read and who can change its rows. If you can't, ask your AI tool to explain the policy to you in plain English, for that specific table.
Step 2: test as a stranger (5 minutes)
Sign out of your app. Ask your coding tool: "Write me a curl command that uses my Supabase public key to select all rows from the profiles table, with no user logged in." Run it. Try your most sensitive tables. You should get an empty list or an error.
Step 3: test as another customer (5 minutes)
Create two accounts, A and B. As A, create something private. Then, signed in as B, ask your tool to fetch A's row by its ID using B's session. You should get nothing.
If any of those return data they shouldn't, don't panic and don't turn RLS off. Ask your AI tool for a policy per table that ties rows to auth.uid(), the ID of the signed-in user, and re-run the tests.
What good looks like
A healthy Supabase app has RLS on for every table, policies you can explain, no secret key anywhere near the browser, and a two-account test you re-run whenever you add a table. That last habit matters most, because new tables are where the gaps come back.
This is item one on our pre-launch security checklist. If you'd like someone to run the stranger and two-account tests against your live app for you, along with the rest of the list, that's what a VibeGuard check does.