Breach report
The vibe-coding RLS epidemic: AI-built apps shipped with no lock on the database
What happened
Lovable is an AI application builder: describe an app in natural language and it generates a working full-stack product, commonly backed by Supabase (a hosted Postgres). Researchers found that a large share of these AI-generated apps shipped with Row-Level Security (RLS) missing or left at defaults.
RLS is the database-level control that decides which rows a given user is allowed to see. Without it, Supabase's public "anon" key — which ships in the app's frontend by design and is therefore visible to anyone — can read tables directly. A scan of 1,645 Lovable-built applications found roughly 170 (about 10%) exposing private data this way. The flaw was assigned CVE-2025-48757 with a CVSS score of 9.3.
Root cause
The AI generated software that ran and looked correct while omitting the security invariant that mattered: access control on the data. "It works" was satisfied; "a stranger with the public key can read every row" was never tested. This is the defining failure mode of vibe-coding — functional output with absent security properties — and it maps directly to OWASP's number-one web risk, Broken Access Control.
How it would have been caught
An authorization test suite that queries each table using only the public anon key, and asserts that private rows are denied, would have caught this before launch. So would a configuration check that verifies RLS is enabled on every table. The reproduction is direct: read a private table with just the public key.
How to prevent it
- Enable Row-Level Security (or equivalent authorization) on every table by default, with deny-by-default policies. Never rely on the client to enforce access.
- Treat AI-generated backends as untrusted drafts: run the access-control gate before any deploy, not after.
- Keep the public key public in your threat model — assume an attacker has it, and design so that changes nothing they can read.
The Breachwire test (red → green)
Query a private table with only the public anon key and confirm it returns rows — the RED control proving the data is reachable. Enable RLS with deny-by-default policies, then confirm the same anon-key query now returns nothing / is denied, while the row's legitimate owner can still read it when authenticated.