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.
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
- 20 March 2025: Matt Palmer finds that a Lovable-built site, Linkable, returns every row of its
userstable when a network request is modified. - 21 March 2025: A script scans 1,645 sites from Lovable Launched, Lovable's showcase. It finds 303 endpoints across 170 projects (about 10.3%) with inadequate Row Level Security.
- 24 May 2025: A follow-up test on Linkable shows RLS now applies to signed-in requests, but removing the authorization header turns the request anonymous and both reads and writes go through again.
- 29 May 2025: CVE-2025-48757 is published. It covers Lovable projects that use a database and were created on or before 15 April 2025, "but may also affect projects created after that date". Fixed versions: none listed, because the fix lives in each project's database.
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:
- Load the app's homepage and record its network requests.
- Find requests going to the database, such as
https://xxx.supabase.co/rest/v1/users. - Modify the request to ask for everything, e.g.
?select=*. - 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:
- RLS off on a table. The anon key can read and write the whole table.
- RLS on, but with a policy like
using (true). The dashboard shows a shield, and everyone can still read every row. - Policies that only cover signed-in users. The 24 May Linkable test is the clearest example: the policy worked with a login token and failed without one, because the anon role had its own, wider access.
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.
- Open your live site, then DevTools → Network. Filter for
supabase.co(or your database host). - Copy the project URL and the
apikeyheader value (the anon orsb_publishable_key). - 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"[]or a permission error: an anonymous visitor gets nothing. Good.- A row of real data: anyone on the internet can read that table.
- Do the same for any
rpc/functions and edge functions the app calls. A function named likeget_..._keyshouldn't return a secret to an anonymous caller. - In the Supabase SQL editor, list every policy and read its
usingandwith checkclauses:
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).
Fix steps
- Turn on RLS for every table in
public:
alter table public.profiles enable row level security;- 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.
- 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.
- Test signed out as well as signed in. Repeat the curl test without an
Authorizationheader and with a second test account, to make sure user A can't read user B's rows. - 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.
Sources
- Matt Palmer, "CVE-2025-48757" (29 May 2025)
- Matt Palmer, "Statement on CVE-2025-48757"
- Lovable docs, Security best practices