If you built an app with Lovable on Supabase, check right now whether Row Level Security is enabled on your tables, because the vulnerability behind CVE-2025-48757 was Lovable-generated apps shipping with Row Level Security disabled by default, which left more than 170 production apps with fully readable, writable, and deletable databases through the public anon key. The response is an audit followed by containment: confirm which of your tables lack Row Level Security or use permissive policies, enable Row Level Security and write correct policies, rotate any exposed keys, and check your data for signs of access. This is a configuration problem you can fix, not a flaw in Supabase or in Row Level Security itself.
Short answer
Audit your Lovable app's Supabase tables for missing or permissive Row Level Security, then contain and fix. Per the CVE-2025-48757 analysis, Lovable-generated projects shipped with Row Level Security disabled by default, so the public anon key could read, modify, and delete any row. Per Supabase's Row Level Security docs, a table with Row Level Security off is fully open to the anon key. Check each table's Row Level Security status, test with the anon key that you cannot reach other users' data, enable Row Level Security with policies tied to the signed-in user, and rotate a service_role key if it was ever exposed.
What the vulnerability is
The Lovable Row Level Security vulnerability, tracked as CVE-2025-48757, is that many Lovable-generated apps were deployed with insufficient or missing Row Level Security on tables reachable directly from the client. Because Supabase apps talk to the database using a public anon key embedded in the app, a table without Row Level Security is open to anyone, so the vulnerability meant that unauthenticated attackers could read, change, or delete any row through the public database endpoint. It is a configuration weakness in the generated app, not a defect in Supabase.
The scale is what made it notable. Researchers found more than 170 production apps with fully accessible databases, exposing personal information, phone numbers, API keys, payment details, and other sensitive data across hundreds of Supabase endpoints. The exposure came entirely from the anon key reaching data that Row Level Security should have restricted, which is why the fix is at the Row Level Security layer. If you built with Lovable, the practical question is not whether the vulnerability class is serious, it is, but whether your specific app is affected, which you can determine directly.
Supabase defaults: why Lovable apps shipped exposed
The root cause traces to defaults. In Postgres, and therefore Supabase, a newly created table does not enforce Row Level Security unless you enable it, and Lovable-generated schemas were created without enabling it, so tables shipped in an open state. Combined with the anon key that Supabase apps expose by design, this meant the generated app was directly queryable by anyone, because the one control that would restrict the public key was not turned on.
This is why the vulnerability was so widespread rather than a one-off mistake: it flowed from a default that applied across generated projects. Understanding it as a default helps you check your own app correctly, because you should not assume Row Level Security is on just because your app works. An app with Row Level Security disabled works perfectly for legitimate users while being wide open, so functioning normally is not evidence of being secure. The only way to know is to look at the Row Level Security status of each table directly, which is the first audit step.
How Row Level Security gets bypassed here
Even where Row Level Security exists, a few patterns leave data exposed in these apps, and knowing them tells you what to look for. The first is Row Level Security simply not enabled, the core CVE case, where the anon key reaches everything. The second is Row Level Security enabled but with a policy that permits everyone, for example a policy whose condition is always true, which technically has Row Level Security on while granting universal access, so the table is public despite appearing protected.
The third pattern is a service_role key exposed in the client. The service_role key bypasses Row Level Security entirely and grants full access, so if a Lovable app shipped that key into the frontend, no policy matters because the key overrides all of them. Each of these produces the same result, data readable and writable by anyone, through a different mechanism, so your audit has to check all three: whether Row Level Security is on, whether any policy is permissive, and whether the service_role key is anywhere in your client.
Is your app affected? How to check
Determining whether your app is affected is a direct, three-part check you can do now. First, in your Supabase dashboard, review every table in your exposed schema and confirm Row Level Security is enabled on each, since any table with it off is open. Second, examine the policies on tables that do have Row Level Security enabled, and flag any policy that grants access unconditionally rather than tying it to the authenticated user. Third, test as an attacker would by using your anon key to query your database endpoint and attempting to read data that should be private, confirming the database rejects it.
Also check your client for the service_role key, since its presence overrides everything. Look through your app's shipped code and bundle for the service_role key value or references to it, and treat any occurrence as a serious exposure. If all your exposed tables have Row Level Security enabled with user-scoped policies, no policy is unconditionally permissive, the anon key cannot reach private data in your test, and the service_role key is nowhere in the client, your app is not affected. If any check fails, it is, and you move to containment.
Immediate response: contain and rotate
If your app is affected, contain it before anything else. Enable Row Level Security on every exposed table immediately and add correct policies, which stops the open access at once, and remove any unconditionally permissive policy. Because the exposure means data could have been accessed, review your database and any available logs for unexpected reads, writes, or deletions, and restore from a backup if data was altered or removed.
Then handle keys. If a service_role key was present in your client, treat it as compromised and rotate it in the Supabase dashboard right away, then move any operation that needed it to a server, since it must never live in the app. The anon key does not generally need rotating, because it is public by design and safe once Row Level Security constrains it, but a leaked service_role key is a full compromise and must be replaced. Enabling Row Level Security stops the bleeding, and rotating an exposed secret closes the more dangerous hole.
Fix: enable Row Level Security and write policies
The lasting fix is correct Row Level Security on every table, which is quick to apply. Enable Row Level Security on each exposed table, after which it denies all access by default, then write policies that grant only the access your app needs, typically allowing users to read and write only their own rows by comparing an owner column to auth.uid(), the signed-in user's identifier. Write separate policies per operation and deliberately grant nothing extra, so a request to read or delete another user's data is rejected.
Verify the fix the same way you audited: use the anon key to attempt access you should not have, ideally as different users, and confirm the policies block it. Make enabling Row Level Security part of your process for any new table rather than a one-time cleanup, since the vulnerability came from a table shipping without it. With Row Level Security on and user-scoped policies in place, the public anon key becomes safe again, which is the state a Supabase app is supposed to be in.
Vulnerability patterns and fixes
Matching each pattern to its fix directs your audit. The table below pairs them.
| Pattern | Why it exposes data | Fix |
|---|---|---|
| Row Level Security not enabled | The anon key reaches every row | Enable Row Level Security on the table |
| Policy that is always true | Grants access to everyone | Replace with a policy scoped to auth.uid() |
| service_role key in the client | It bypasses Row Level Security entirely | Rotate it and move it server-side |
| Permissive exposed schema | Tables are directly queryable | Enable Row Level Security and restrict access |
Read the table against your own app: check each pattern, since the CVE-class exposure can come from any of them, and functioning normally does not rule any of them out.
Audit checklist
Working through these steps determines your exposure and fixes it. The checklist below covers them.
| Step | Action | Done? |
|---|---|---|
| Check Row Level Security status | Every exposed table has it enabled | [ ] |
| Check policies | No policy grants access unconditionally | [ ] |
| Test with the anon key | Cannot read or write private data | [ ] |
| Check for service_role | Not present anywhere in the client | [ ] |
| Rotate if exposed | Roll a leaked service_role key | [ ] |
| Verify the fix | Re-test access with the anon key | [ ] |
The step that decides most cases is checking the Row Level Security status of every exposed table, because the core CVE exposure is simply a table shipping with it off.
Scan your app for the exposure
Row Level Security lives in Supabase, but part of this vulnerability lives in the app you shipped: a service_role key bundled into the client bypasses every policy you set, so confirming what keys actually ship is a necessary companion to the database audit.
A scanner like PTKD.com analyzes your app build and reports issues such as leaked keys and secrets, insecure data storage, and over-broad permissions by severity, mapped to OWASP MASVS, so a service_role key that reached the client is flagged, while the anon key is expected. To be clear about the boundary: PTKD does not check your Supabase Row Level Security policies, which you audit in the dashboard, and it does not enable them for you. It confirms your shipped app does not carry a secret that would defeat the Row Level Security you fix.
What to take away
- The Lovable Row Level Security vulnerability, CVE-2025-48757, was apps shipping with Row Level Security disabled by default, exposing 170-plus databases through the public anon key.
- It stems from a Supabase default: a new table does not enforce Row Level Security unless you enable it, and an open table works normally while being fully exposed.
- Data is exposed through three patterns: Row Level Security off, a policy that is always true, or a service_role key in the client, so audit for all three.
- Check every exposed table's Row Level Security status, test with the anon key, and look for a service_role key in your client to determine if you are affected.
- If affected, enable Row Level Security with user-scoped policies immediately, rotate a leaked service_role key, and scan the shipped app with a tool like PTKD.com.




