If you found this page after seeing a security advisory about your Lovable.dev app, or after a friend pointed out that your Supabase tables read straight from a browser, this is the page that walks you through the fix in order. The vulnerability has a CVE, a documented attack vector, and a small set of policies that close it.
Short answer
The bypass works because Lovable's AI creates Supabase tables without consistently enabling Row Level Security, and the public anon_key shipped in the client lets anyone query those tables directly. According to Matt Palmer's CVE-2025-48757 disclosure published on May 29, 2025, 303 endpoints across 170 Lovable projects were exposed at the time of publication. Fix it by enabling RLS on every table and replacing any USING (true) policy with auth-scoped checks.
What you should know
- CVE-2025-48757 documents the exact attack pattern, published after a 45-day coordinated disclosure window that closed without a meaningful Lovable fix.
- The anon_key is public by design. Rotating it does not help; the missing piece is the RLS policy.
- Lovable's 2.0 security scan checks policy existence, not effectiveness. A
USING (true)policy passes the scan while leaving the table fully open. - An app that ships secure can regress. Lovable's AI adds new tables as features ship and does not always carry forward the policy pattern from existing tables.
- The attack works without authentication. An attacker opens devtools, copies the anon_key, and runs queries against
*.supabase.codirectly.
How does the RLS bypass actually work?
Supabase's API layer (PostgREST) translates HTTP requests into SQL queries, executed under one of two roles: anon for unauthenticated traffic and authenticated for logged-in users. According to Supabase's official documentation on Row Level Security, RLS policies act "like adding a WHERE clause to every query." When a table has no policy, or has a USING (true) policy, the WHERE clause is effectively absent and every row is returned.
The Lovable bundle ships the project URL and the anon_key as static strings in the JavaScript that any visitor downloads. Both are meant to be public, paired with proper RLS policies. The CVE entry shows the exploit reduces to three lines: open devtools, read the values from the network panel, then fetch https://<project>.supabase.co/rest/v1/<table>?select=* with the anon_key in the apikey and Authorization headers. No login required.
Lawrence has seen this pattern repeat across audits of vibe-coded apps that started as a single-table prototype and grew. The first table got a policy. The fifth one, added six weeks later by a different AI prompt, did not.
What did CVE-2025-48757 actually expose?
The data inventory across the 170 documented projects is broad. The Superblocks technical writeup of the CVE lists emails, usernames, phone numbers, payment statuses, API keys for Gemini and Google Maps, developer credentials, home addresses, personal debt amounts, and Stripe integration endpoints that accepted payment parameter injection.
A February 2026 follow-up audit by VibeEval scanned 1,645 Lovable apps and found that more than 170 still had fully exposed databases. One showcased EdTech app exposed 18,697 user records, with authentication logic that, in the auditor's words, "blocked logged-in users and let anonymous ones through."
The specific exploit was not novel. PostgREST has documented how query parameters work since launch. What was new was the volume: 170 production apps shipped by Lovable users who trusted the platform's defaults more than their security team would have.
How do you find the broken tables in your own app?
Four checks, in order of confidence:
- Open the Supabase dashboard, go to Authentication, then Policies. Every table that holds user data should appear with one or more policy rows. Tables marked as "RLS disabled" are public.
- For each policy, open the body. Anything that reads
USING (true)is functionally equivalent to no policy at all for the operation it covers (SELECT, INSERT, UPDATE, or DELETE). - From a browser in incognito mode (no logged-in session), open devtools, copy the anon_key from your bundle, and try to query each sensitive table. If you get rows back, the policy is broken.
- Run Lovable's built-in security scan as a baseline, but do not trust it. The scan tells you which tables are obviously exposed; it does not tell you which policies are permissive in practice.
For mobile apps built on top of a Lovable backend, PTKD.com (https://ptkd.com) is one of the scanners that maps Supabase endpoints out of a compiled APK or IPA and flags the ones that respond to unauthenticated queries. The report ties findings to the relevant OWASP MASVS controls and recommends specific policy patterns per table type.
What does a correct RLS policy look like?
The correct pattern depends on the access shape of the table. The three patterns that cover most Lovable schemas:
| Table type | Correct pattern | Why this and not the alternatives |
|---|---|---|
| User-owned records (todos, notes, files) | USING (auth.uid() = user_id) | Each user only sees their own rows. The auth.uid() function returns the JWT-validated user id, not a client-provided value. |
| Tenant-scoped records (multi-org apps) | USING (org_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid())) | Joins against a membership table so admins of an org can see all org rows but not other orgs. |
| Public read, authenticated write | USING (true) for SELECT, USING (auth.uid() IS NOT NULL) for INSERT/UPDATE | Public read is intentional for catalog or blog tables. Writes still need an authenticated session. |
The trap is the third row. A USING (true) policy on SELECT for a public catalog is correct; the same body on a user-data table is the vulnerability. The check is whether the table holds anything that should not appear in a search engine result.
For INSERT and UPDATE on user-owned tables, add a WITH CHECK clause as well: WITH CHECK (auth.uid() = user_id). The USING clause filters the rows the query can read; WITH CHECK filters the rows the query is allowed to write. Without both, a user can read their own rows but update someone else's.
What about Lovable's built-in security scan?
Lovable released the security scan feature in version 2.0 on April 24, 2025, three weeks after Palmer's initial disclosure. The scan reports the number of tables with RLS enabled and flags tables without policies. Per the published CVE writeup, the scan does not evaluate whether the policies actually restrict access.
In practice this means a table with ENABLE ROW LEVEL SECURITY and a single USING (true) policy gets a green check from the Lovable scanner while remaining fully readable from any browser. Treat the scan as a low-bar smoke test, not a security audit.
What to watch out for
Three details that get missed during the rush of a fresh disclosure:
First, Supabase Auth tables (auth.users in particular) are not in your project schema and have their own access rules. Querying auth.users directly from the client returns nothing for the anon role even without RLS policies; the table is hidden behind the auth schema. The exposure happens when developers create a profiles table in the public schema and mirror auth data into it without an RLS policy.
Second, the JWT aud claim is not the same as auth.uid(). Earlier versions of Supabase Auth issued JWTs with a generic aud of authenticated; some Lovable templates wrote policies that checked the audience instead of the user id, which let any logged-in user see every other logged-in user's data. The 2025 dev.to audit of 50 Lovable apps found this pattern in 28% of audited projects.
Third, fixing the policies does not retroactively unbreach the data. If your access logs show queries from unexpected IPs in the weeks before the fix, treat the affected records as compromised and follow your standard incident-response steps. Supabase retains query logs for seven days on the free tier and longer on paid plans.
Key takeaways
- The Lovable.dev RLS bypass works because anon_key plus missing or permissive policies equals public data. Rotating the anon_key does not help.
USING (true)is the policy body to grep for. It is the AI's most common shortcut and the easiest one to leave in production.- Lovable's security scan checks existence, not effectiveness. Audit policy bodies by hand or with a third-party scanner.
- For Lovable apps compiled to mobile, PTKD.com (https://ptkd.com) scans the APK or IPA and flags Supabase endpoints that return data without authentication.
- Document the policy review in your CHANGELOG so the next AI-generated migration cannot quietly revert the fix.




