Lovable Supabase RLS not enabled: anyone can read your app's data (CVE-2025-48757)
Symptoms
- The app works perfectly and shows no errors; there is no signal anything is wrong
- Any visitor can query your database tables directly using the public anon key that ships in the client bundle
- Other users' emails, addresses, payment info, and stored API keys are readable, and often writable
- A 2025 scan of 1,645 public Lovable projects found 170 (about 10%) with inadequate RLS, exposing 303 endpoints
- The pattern was assigned CVE-2025-48757
Why it happens
Tables were created without Row Level Security
Postgres tables created via raw SQL or AI-generated migrations do not get RLS enabled by default, and Lovable's AI historically ran CREATE TABLE without adding ENABLE ROW LEVEL SECURITY or any policies.
Supabase's auto-API serves every row of an unprotected table
PostgREST exposes every table in the public schema, and without RLS it returns every row to any request bearing the anon key, which is public by design.
There is no failure signal
Nothing errors and nothing looks broken, so the builder never learns the data is exposed until a scanner, a stranger, or a breach finds it first.
How to fix it
- Find every exposed tableIn the Supabase dashboard, open Database > Tables and check the RLS column, or run Security Advisor under Database > Advisors, which flags every public-schema table with RLS disabled. This is a live exposure while you work, so do this now.
- Enable RLS on each flagged tableFor every exposed table, run: ALTER TABLE public.your_table ENABLE ROW LEVEL SECURITY; Repeat for each table Security Advisor flagged. Enabling RLS is the lock; the policies in the next step decide who gets a key.
- Add explicit policies per operationCreate a policy for each operation your app performs. For reads: CREATE POLICY "Users read own rows" ON public.your_table FOR SELECT TO authenticated USING ((select auth.uid()) = user_id); Repeat for INSERT (using WITH CHECK), UPDATE, and DELETE.
- Write (select auth.uid()), not bare auth.uid()Use (select auth.uid()) in policy clauses so Postgres evaluates it once per query instead of once per row. Same security, much better performance on large tables.
- Test as an outsiderSign in with a second account in an incognito window and confirm you cannot read another user's rows. Then make a plain curl request using only the anon key and verify it returns nothing it should not. The anon key is public, so this test simulates any visitor on the internet.
- Make Lovable audit the restIn chat, ask Lovable to 'review all Supabase tables and enable RLS with owner-scoped policies'. Then re-run Security Advisor and confirm zero findings before you call this closed.
- Assume the data already leakedHonest note: enabling RLS stops future reads, it does not undo past ones. Assume any data that sat in an RLS-less table was already read, and rotate any secrets or API keys that were stored in it.
How to prevent it
- Run Security Advisor after every AI-generated migration or schema change.
- Tell the AI to include ENABLE ROW LEVEL SECURITY and owner-scoped policies in every table-creation prompt.
- Test each new feature with a second, non-owner account before shipping.
- Never store third-party secrets in database tables the client can reach.
- Treat the anon key as public, because it is; RLS is the only thing between it and your data.
Tools that actually fix this
Recommended because they address the failure mode above, not because of the payout. Some are affiliate links; see how we choose.
If your AI-built app uses Supabase, Row Level Security is the actual fix for exposed data, and it is free. The dashboard's Security Advisor lists every table you left open.
Try Supabase →Drop-in authentication that handles sessions, tokens, and protected routes properly, so you stop shipping the hand-rolled auth an AI guessed at. Generous free tier for a real app.
Try Clerk →Frequently asked questions
What is CVE-2025-48757?
CVE-2025-48757 is the identifier assigned to the pattern of Lovable-built apps shipping Supabase tables without Row Level Security, leaving user data readable through the public anon key. A 2025 scan of 1,645 public Lovable projects found 170, about 10%, with inadequate RLS, exposing 303 endpoints. It is not a bug in one app; it is a default-configuration failure repeated across many.
Is the Supabase anon key safe to be public?
Yes, the Supabase anon key is public by design and ships in every client bundle, but it is only safe when Row Level Security is enabled with correct policies on every table. Without RLS, the anon key grants any visitor read (and often write) access to entire tables through Supabase's auto-generated API. The service_role key is different: it bypasses RLS entirely and must never appear client-side.
How do I check if my Lovable app's database is exposed?
Open the Supabase dashboard, go to Database > Advisors, and run Security Advisor, which flags every public-schema table with RLS disabled. You can also open Database > Tables and read the RLS column directly. If any table your app uses shows RLS off, anyone holding the anon key from your bundle can query it.
Does turning on RLS fix data that already leaked?
No. Enabling Row Level Security stops future unauthorized reads, but anything that sat in an RLS-less table may already have been read, and nothing errors to tell you either way. Rotate any secrets or API keys that were stored in exposed tables, and treat leaked personal data as a disclosure question, not just a configuration fix.
Sources
- Vibe App Scanner: Supabase Row Level Security
- byteiota: Supabase security flaw, 170 apps exposed by missing RLS
- Superblocks: Lovable vulnerabilities
- PTKD: Lovable.dev Supabase RLS bypass vulnerability
- Supabase docs: Row Level Security
- Ship Safe: Lovable security vulnerabilities
Related errors
Supabase Row Level Security is off: your whole database is readable with the anon key
'new row violates row-level security policy' in Supabase (403 / error 42501)
Lovable API key exposed: secrets visible in your client-side code
No auth on your AI-generated API endpoints: anyone can call your backend
The AI put your API key in the frontend: OpenAI, Stripe, or Supabase keys visible in the JS bundle
The Vibe Oops briefing
One email when something ships to production that should not have. New incidents, new error guides, no filler.