CVE-2025-48757 is a critical vulnerability affecting Lovable-generated apps that use Supabase as a backend. The root cause: missing or misconfigured Row Level Security (RLS) policies that allowed unauthenticated users to read and write entire database tables.
The public research that surfaced this found 1,645 Lovable apps with active Supabase backends. Of those, 170+ had exploitable RLS gaps — 303 vulnerable endpoints in total. User emails, payment records, tokens, and API keys were exposed to anyone who knew how to make a direct Supabase API call.
If your app was built with Lovable and uses Supabase, treat this as a live risk until you have personally verified your RLS configuration.
What is CVE-2025-48757?
CVE-2025-48757 is classified as an information disclosure and broken access control vulnerability (CWE-863) in Lovable-generated applications. The official description: insufficient Row Level Security policies on Supabase databases allowed remote unauthenticated attackers to read and modify data in production apps.
The National Vulnerability Database entry rates this CVSS 9.3 — critical.
The key facts:
- Affected apps: Lovable-generated projects using Supabase, particularly those deployed without a dedicated security review.
- Attack type: Remote, unauthenticated. No account required.
- Data exposed: User profiles, emails, payment records, API tokens, hashed passwords — whatever was stored in tables without correct RLS.
- Scale: 170+ apps confirmed vulnerable; 303 exploitable endpoints identified across 1,645 scanned apps.
- Root cause: Missing RLS, or RLS enabled but policies set to
USING (true)or equivalent — which permits all access.
How the vulnerability actually worked
Supabase exposes every project's database through a public REST API. To authenticate requests, clients use a public anon key that is intentionally embedded in client-side code. This design is safe — but only when Row Level Security policies are in place and correctly configured.
In vulnerable Lovable apps, one of two things was true:
- RLS was never enabled. Every table was fully readable and writable by anyone with the anon key.
- RLS was enabled, but the policy was
USING (true)— which evaluates to true for every row on every request, including unauthenticated ones.
The attack flow:
- Open the Lovable app in a browser. Inspect the JavaScript bundle or network requests. Find the Supabase project URL and anon key — both are present by design.
- Construct a direct Supabase client with those credentials, or call the PostgREST REST API directly.
- Because RLS is missing or permissive, a query like
select * from usersreturns every row in the table — no login required. - In some cases,
insert,update, anddeletealso work — allowing data tampering, not just disclosure.
The app's UI only showed each user their own data. Founders assumed the backend enforced the same restriction. It did not.
Why Lovable apps were systematically affected
Lovable generates code from prompts. The generated Supabase schema and policies were syntactically correct — they compiled, they ran, the app worked in happy-path testing.
The problem was semantic. AI code generation resolves "allow users to read their data" to the simplest working SQL:
CREATE POLICY "Enable read access for all users"
ON public.users
FOR SELECT
USING (true);
This policy does what it says: it allows all users to read all rows. But it does not restrict by user identity. Any request — authenticated or not — gets every row.
The correct policy requires ownership enforcement:
CREATE POLICY "Users can read own rows"
ON public.users
FOR SELECT
USING (auth.uid() = id);
auth.uid() returns the UUID from the authenticated user's JWT. If no user is logged in, it returns null — which never matches a real row ID. Unauthenticated requests get nothing.
The gap between USING (true) and USING (auth.uid() = id) is one token of SQL. The difference in data exposure is every row in the database.
Who is still at risk
CVE-2025-48757 is not only a historical incident. The class of vulnerability — missing or overly permissive RLS on Supabase-backed apps — affects any AI-generated app built on this stack, not just Lovable.
You are at risk if:
- Your app was scaffolded by an AI builder (Lovable, Bolt, Cursor, or similar) and you have not manually reviewed every Supabase RLS policy.
- You added new tables after the initial build without verifying RLS was enabled and configured with ownership policies.
- Your app was audited once at launch but has since had schema changes.
- You use
USING (auth.role() = 'authenticated')instead ofUSING (auth.uid() = user_id)— this restricts to logged-in users, but any logged-in user can read any other user's rows.
Independent research scanning 1,072 Supabase-backed vibe-coded apps found 98% had security issues. 16% had critical flaws. Missing or misconfigured RLS was the most common finding.
How to check if your app is affected
Option 1: Run a VibeScan
Paste your app's URL into VibeScan. The URL scan probes your Supabase public surface using the anon key — the same way an attacker would — and flags tables that respond with data to unauthenticated requests or detect common RLS misconfigurations.
Takes under two minutes. No code access required.
Option 2: Check manually in Supabase
Go to Supabase Dashboard → Authentication → Policies.
For every table that stores user data, read the USING clause on each SELECT policy. The dangerous patterns:
USING (true) -- Open to everyone
USING (auth.role() = 'authenticated') -- Any logged-in user sees all rows
USING (auth.uid() IS NOT NULL) -- Same problem
The safe pattern:
USING (auth.uid() = user_id) -- User sees only their own rows
Also verify:
- RLS is enabled on every table — not just the ones you remember adding policies to. New tables created after the initial build often have RLS off by default.
- INSERT, UPDATE, and DELETE policies exist, not just SELECT. Each operation needs its own policy.
- Storage buckets have policies on
storage.objectsthat restrict access by ownership. - RPC functions check
auth.uid()at the start of the function body, not just rely on the calling table's RLS.
Option 3: Test from an unauthenticated context
Use the Supabase JavaScript client with only the anon key — no user logged in. Try querying your most sensitive tables:
import { createClient } from "@supabase/supabase-js";
const supabase = createClient(YOUR_PROJECT_URL, YOUR_ANON_KEY);
// If this returns rows, your RLS is not working
const { data } = await supabase.from("users").select("*");
console.log(data);
If data contains any rows, your SELECT policy is not enforcing user-level restrictions.
How to fix it
1. Enable RLS on every table
In the Supabase SQL editor:
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.orders ENABLE ROW LEVEL SECURITY;
-- Repeat for every table that stores user data
2. Replace permissive policies with ownership policies
Drop the generated policies and create correct ones:
-- Remove the dangerous generated policy
DROP POLICY IF EXISTS "Enable read access for all users" ON public.orders;
-- Add correct per-user policies for all four operations
CREATE POLICY "Users can read own orders"
ON public.orders FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can insert own orders"
ON public.orders FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own orders"
ON public.orders FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can delete own orders"
ON public.orders FOR DELETE
USING (auth.uid() = user_id);
3. Keep the service_role key server-side only
The anon key is safe to expose in frontend code — it is designed for client use. The service_role key bypasses all RLS. If it is in your frontend bundle, rotate it immediately in Supabase Dashboard → Settings → API, then update your server-side environment variables.
4. Lock down Supabase Storage
If your app stores user files:
-- Private bucket: users can only read their own files
CREATE POLICY "Users can read own files"
ON storage.objects FOR SELECT
USING (auth.uid()::text = (storage.foldername(name))[1]);
5. Add auth checks to RPC functions
Any Postgres function exposed via the Supabase REST API should verify the caller's identity at the start:
CREATE OR REPLACE FUNCTION get_my_data()
RETURNS TABLE(...)
LANGUAGE plpgsql
SECURITY INVOKER
AS $$
BEGIN
IF auth.uid() IS NULL THEN
RAISE EXCEPTION 'Unauthorized';
END IF;
-- ... rest of function
END;
$$;
What Lovable changed — and what it does not cover
After CVE-2025-48757, Lovable introduced security features: a dashboard check for enabled RLS, AI warnings when secrets appear in prompts, and compliance milestones (SOC 2 / ISO 27001).
These help new projects. They do not automatically fix existing apps with misconfigured policies. And they do not verify that USING clauses contain correct ownership logic — only that RLS is toggled on.
The NVD entry for CVE-2025-48757 explicitly states that responsibility for correct RLS configuration sits with the app owner, not the platform. That is the accurate position. The platform sets defaults; you are accountable for what ships.
Frequently asked questions
What is CVE-2025-48757 in plain terms? Missing or misconfigured Row Level Security in Lovable-generated Supabase apps. Unauthenticated attackers could read and write entire database tables — user data, payments, credentials — without logging in.
How do I know if my Lovable app is affected?
Check every SELECT policy on every table containing user data. If any USING clause is true, auth.role() = 'authenticated', or auth.uid() IS NOT NULL, you have the same vulnerability class. Run a VibeScan for a quick automated check.
Is this a Supabase bug? No. Supabase RLS works correctly when policies are written correctly. The vulnerability was in how Lovable scaffolded those policies — not in the Postgres or Supabase engine.
Can this happen in apps built with other AI tools?
Yes. Any AI builder that generates Supabase schema without enforcing ownership-based RLS policies produces the same pattern. Bolt, Cursor, and custom GPT-based scaffolding tools have all been found to produce USING (true) or equivalent policies.
Do I need to notify users if my app was affected? If you have evidence or reason to believe user data was accessed without authorization, consult your jurisdiction's data breach notification requirements. Many jurisdictions require disclosure within 72 hours of becoming aware of a breach affecting personal data.
Sources: CVE-2025-48757 NVD entry; Matt Palmer's original research (1,645 apps, 170+ affected, 303 endpoints); SecurityOnline.info CVE write-up; Supabase Row Level Security documentation; PreBreach OWASP in AI-Generated Code (Feb 2026).