DEV Community

jjames101103
jjames101103

Posted on

The RLS Mistake That Exposed 170 Real Lovable Apps — 3 Checks You Can Run Today

If you built your app with Lovable, Bolt, Replit, v0, or Base44, there's a good chance you've never once looked at your database's access-control settings. Most people who build this way don't come from a backend background, and these tools are good enough at getting you to "it works" that you never find out whether "it works" also means "anyone on the internet can read your users table."

In 2025 a researcher named Matt Palmer scanned 1,645 live Lovable apps and found that 170 of them (10.3%) had exposed databases — leaking real emails, payment details, and API keys to anyone who knew where to look. No hacking involved. Just a missing Row-Level Security (RLS) policy on a Supabase table. It's since been catalogued as CVE-2025-48757, and it's not a one-time thing — Base44 and Replit have each had their own public versions of the same story.

The good news: checking for this yourself takes about five minutes and doesn't require knowing how to code.

Why this happens

Supabase (the database most of these builders default to) ships with an anon key that's meant to be public — it's sitting in your app's JS bundle right now, visible to anyone who opens dev tools. That's fine by design, as long as every table with real data has a Row-Level Security policy that says who's allowed to read or write which rows.

The problem is that RLS is opt-in, not opt-on-by-default, and an AI builder prompted to "add a users table" will very often create the table without ever being asked to also lock it down. The app looks and works identically whether the table is protected or wide open — there's no visual cue, no error, nothing that would tip you off.

Three checks you can run right now

1. Check if RLS is even turned on.
Open your Supabase project → Table Editor → pick any table that stores user data (profiles, orders, messages, anything with a user_id column). Look at the shield icon next to the table name in the sidebar. If it's not showing "RLS enabled," that table is readable and writable by anyone with your anon key — which, again, is public by default.

2. Check that RLS being "enabled" isn't just theater.
Enabling RLS with zero policies attached actually blocks all access, which will look like your app is broken — so if you did turn it on and then things stopped working, the fix a lot of AI builders reach for is a policy like:

create policy "allow all" on public.profiles
for all using (true);
Enter fullscreen mode Exit fullscreen mode

That technically has RLS "enabled," and is functionally identical to having no RLS at all. Go to Authentication → Policies and actually read what each policy says. A real policy should reference auth.uid(), e.g.:

create policy "users can only see their own profile" on public.profiles
for select using (auth.uid() = user_id);
Enter fullscreen mode Exit fullscreen mode

3. Check your deployed site for a leaked service-role key.
The anon key is supposed to be public. The service-role key is not — it bypasses RLS entirely and should only ever live in a backend environment variable. View source (Ctrl/Cmd+U) on your live site and search for "service_role" or just eyeball any long key strings — if one of them is your service-role key, it means every RLS policy you just checked is irrelevant, because that key ignores all of them.

If you want a longer version

I put together a free 10-point checklist covering this and a few adjacent issues (CORS config, webhook signature checks, exposed .env values, unprotected admin routes) — no email required, just a static page: https://claude.ai/code/artifact/634324c9-1353-4aa3-a079-0889bd3ce0dd

And if you'd rather not do the check yourself, that same page has a $25 option where I do it manually and send back a plain-English writeup same day. Entirely optional — the checklist above covers the same ground for free if you'd rather DIY it.

Either way: five minutes checking your RLS policies today is a lot cheaper than finding out about a gap the way the 170 apps in that Lovable scan did.

Top comments (0)