83 of 512 public Lovable projects (16.2%) ship a migration policy that lets signed-out visitors update or delete every row of a table. Another 7 (1.4%) let any signed-in user do it. 53 (10.4%) create a table and never enable row level security on it.
We read the code the app builder shipped, not the live databases. No database was queried and no project is named.
I build VibeRaven, an open-source repo check for Vercel + Supabase apps. The scan behind these numbers ran on it.
Why read the code instead of the databases
UpGuard reported 16,326 Supabase databases with tables anyone could read, and pointed at one cause: tables created programmatically through the API, which is how coding agents work, do not get RLS by default. Live scans show what is exposed. They do not show where it came from, so we read the step before the database: the migration files a Lovable project ships with.
What we found
Out of 512 public Lovable projects with their own Supabase migrations:
- 16.2% (83) have a policy that lets signed-out visitors update or delete every row of a table. In another 1.4% (7), a migration revokes the anonymous grant on that table, so any signed-in user can do it instead, and sign-up is usually open. We checked 18 of the 90 by hand and all 18 were real. An independent review of a random 10 confirmed 9; the tenth had dropped the policy inside a dynamic SQL block the scan does not read.
- 10.4% (53) create a table in a migration and never enable RLS on it. Of 4 reviewed independently, 3 were confirmed and 1 could not be decided from the files.
- 8% (41) let anyone read a table with email or phone columns. Newsletter, contact form and lead tables are left out of this number.
- 2.7% (14) commit a service role or secret key in a
.envfile, going by the role inside each key or itssb_secret_prefix. A later full-repo read found 29. - 2.1% (11) let anyone read a password or password hash column.
Policy names promise checks the SQL doesn't make
The pattern that surprised us most. These are verbatim from the scan, projects withheld:
create policy "Owners can update their agents" on public.agents for update using (true); create policy "Admin can update admin users" on public.admin_users for all using (true); create policy "Admins can view their own account" on public.admin_accounts for select using (true); When you skim a migration your agent wrote, you read the name. Postgres only runs the using clause, and using (true) lets every caller through.
The service role policy that opens the table
Another repeat: a policy like "Service role can manage all sessions" with using (true). The service role bypasses RLS anyway, so it never needs a policy. A policy like that only opens the table to everyone else, unless it is limited with to service_role.
Check your own project
Run this in the Supabase SQL editor. Every row is a policy that lets everyone through:
select tablename, policyname, cmd, qual, with_check from pg_policies where schemaname = 'public' and (qual = 'true' or with_check = 'true'); A select on content that is meant to be public is fine. update, delete or all almost never is. Read the qual column, not the policy name.
The repo check reads the same thing from migrations, with file and line, and says when a policy name promises owners or admins that the SQL does not check. On a two-policy fixture, npx -y viberaven@1.7.8 check printed (folder shortened, the monitoring note cut):
viberaven check · ~/agents-app 🔴 A policy lets anyone write every row (rls_policy_allows_all_write) supabase/migrations/20260301000000_agents.sql:9 Policy "Owners can update their agents" on public.agents lets anyone, signed in or not, update every row, to any values: using (true). The name says "Owners can update their agents", but nothing in the policy checks who the caller is. 🟡 A policy lets anyone read every row (rls_policy_allows_all_read) supabase/migrations/20260301000000_agents.sql:8 Policy "Anyone can view agents" on public.agents lets anyone, signed in or not, read every row: using (true). Fine for truly public content; wrong for anything per-user. Verdict: ❌ 1 blocker, 1 warning · score 65 It is a repository check, not a live database test, so run the SQL above against the live project too.
Method and limits
We found public GitHub repos whose package.json includes lovable-tagger, Lovable's build tag, through GitHub code search in October 2026, and kept the 512 with a supabase/migrations folder. Each repo was read with VibeRaven 1.6.1, then filtered to strict criteria: only policies in supabase/migrations count, newsletter and contact tables are excluded from the personal data number, and tables a migration loop may put under RLS are left out of the RLS number. Then samples were checked by hand.
Policies and grants are separate checks in Supabase: a policy only matters for roles that hold a grant on the table. We counted a table as open to signed-out visitors only when no migration revokes the anonymous grant on it. A grant changed outside the migrations would not show up.
The sample is not random. It comes from GitHub search, and public repos lean toward side projects. A repo is also not always what is live; someone may have fixed a table in the dashboard. Treat these numbers as what shipped in the code, not as what is exposed right now.
FAQ
Is using (true) always wrong? No. On a select policy for content meant to be public it is fine. On update, delete or all it lets anyone change or remove every row.
Does this mean 16.2% of Lovable apps are exposed right now? No. These are public repos from GitHub search, and the code is not always what is live.
Sources
- Supabase, Row Level Security
- PostgreSQL, Row Security Policies
Full post: viberaven.dev.
Written with help from Claude. The scan, the hand checks and the numbers are ours.

