Abbi Labs

Breach breakdowns

Breakdown: how 170 Lovable apps left their Supabase data open (CVE-2025-48757)

By Pritesh Ghodge, security engineer · Published 3 November 2026

Is your Supabase data readable by anyone?

The Abbi Labs quick check tests your live app as an anonymous visitor: Supabase tables readable with your public key, secret keys in your JavaScript, exposed .env and .git files. No sign-up.

Scan your app free

Weekly AI-app security checklist

One short email a week: a practical check for apps built with Supabase, Next.js and AI tools (RLS, leaked keys, headers and more). Unsubscribe anytime.

In spring 2025 a researcher scanned sites built with Lovable and found that about one in ten would hand their database contents to anyone who asked. No exploit kit, no password guessing. Just a changed query string. This is the breakdown of what happened, why, and how to check that your own app isn't doing the same thing.

Timeline

How the attack worked

Lovable apps are mostly front end. The browser talks straight to the database (Supabase in the examples) over its REST API, using the public anon key. That's by design: the anon key is meant to be public, and Row Level Security (RLS) policies are what decide which rows each request can see.

The researcher's method, from the write-up:

  1. Load the app's homepage and record its network requests.
  2. Find requests going to the database, such as https://xxx.supabase.co/rest/v1/users.
  3. Modify the request to ask for everything, e.g. ?select=*.
  4. If RLS is missing or too permissive, every row comes back.

The anonymized endpoints in the report show what was sitting behind those requests: users, transactions and subscriptions tables, plus functions that returned third-party secrets (get-google-maps-token, get_gemini_api_key, refresh-ebay-token). The CVE lists PII such as names and email addresses, API keys for other services, and payment data, "including the ability to modify payment status".

The scan only touched homepages. It didn't log in or crawl further, so the real exposure was probably larger.

Root cause

The report is explicit that the problem wasn't a leaked key. Palmer first assumed it was, then realised Supabase anon keys are public by design. The real problem was RLS that was missing, or didn't match what the app actually meant to allow.

Three patterns show up again and again:

The report also criticises Lovable's built-in security scanner at the time for checking that a policy existed, not that the policy was correct. That's worth remembering whatever tool you use: "has a policy" and "is protected" are different questions.

How to check your own app

Only test projects you own.

  1. Open your live site, then DevTools → Network. Filter for supabase.co (or your database host).
  2. Copy the project URL and the apikey header value (the anon or sb_publishable_ key).
  3. For each table you see, run:
curl "https://YOUR-PROJECT.supabase.co/rest/v1/TABLE?select=*&limit=1" \
  -H "apikey: YOUR_ANON_KEY" \
  -H "Authorization: Bearer YOUR_ANON_KEY"
  1. Do the same for any rpc/ functions and edge functions the app calls. A function named like get_..._key shouldn't return a secret to an anonymous caller.
  2. In the Supabase SQL editor, list every policy and read its using and with check clauses:
select tablename, policyname, roles, cmd, qual, with_check
from pg_policies
where schemaname = 'public';

Anything with qual = 'true' for anon or public deserves a second look. The free Supabase RLS policy checker reads this for you in your browser.

Rather not curl every table by hand?

Paste your URL and Abbi Labs runs the anonymous checks for you (one row max per table, nothing stored).

Run a free scan

Fix steps

  1. Turn on RLS for every table in public:
alter table public.profiles enable row level security;
  1. Replace "allow everyone" policies with owner-only ones:
drop policy if exists "Enable read access for all users" on public.profiles;

create policy "own rows"
  on public.profiles for select
  to authenticated
  using ((select auth.uid()) = user_id);

Add matching insert, update and delete policies with with check clauses, so users can't write rows for someone else or change a payment status.

  1. Move secrets out of tables and RPCs. Third-party API keys belong in server-side environment variables or edge-function secrets, never in a table the client can query. If one was exposed, rotate it at the provider.
  2. Test signed out as well as signed in. Repeat the curl test without an Authorization header and with a second test account, to make sure user A can't read user B's rows.
  3. Re-run the checks after every big AI-generated change. Agents that hit a "permission denied" error often "fix" it by loosening a policy.

The takeaway

Building fast with Lovable or any other AI builder isn't the problem. The architecture, where the browser talks straight to the database, is fine if the database rules are right. CVE-2025-48757 showed how often they weren't, in apps polished enough to make a showcase. Spend ten minutes testing yours from the outside, as an anonymous visitor.

Abbi Labs runs these anonymous checks for you (one row max per table, nothing stored), and the free Supabase RLS policy checker reads your policies. Or use the curl test above. It's free.

Scan your app free

Sources

Related guides

Weekly AI-app security checklist

One short email a week: a practical check for apps built with Supabase, Next.js and AI tools (RLS, leaked keys, headers and more). Unsubscribe anytime.