cd /news/ai-tools/58-of-154-public-supabase-apps-had-a… · home topics ai-tools article
[ARTICLE · art-138958] src=dev.to ↗ pub= topic=ai-tools verified=true sentiment=↓ negative

58 of 154 public Supabase apps had a working service_role key in git

A security scan of 154 publicly accessible Supabase-backed apps found that 58 had a working service_role key exposed in their git history, according to a developer who published the findings. The service_role key bypasses Row-Level Security entirely, allowing anyone who finds it to read or delete data through the REST API. The developer attributed the leaks to AI coding tools scaffolding .env files with real credentials, dev-style filenames that evade .gitignore patterns, and keys persisting in git history after deletion.

by read3 min views2 publishedSep 24, 2026

If you build with Lovable, Bolt, Cursor, or any AI coding tool on top of Supabase, this week's scan has a number you should see: 58 of 154 public apps shipped a working service_role key inside their git history.

That key is the master key for the database. It bypasses Row-Level Security entirely — the same RLS you turned on in the dashboard does not apply to it. Anyone who finds it can run DELETE FROM "user" over the REST API and the database believes it.

I did not read a single row of anyone's data. I verified the key decodes to a real project (iss, ref, and a service_role role claim), checked that the project is live, and moved on. That is enough to know the exposure is real.

Three causes, in the order I actually saw them:

AI tools scaffold .env files with real keys. Your AI agent opens the Supabase dashboard to "wire up the database," copies the project URL and keys into .env, and commits it because the app "won't build" otherwise. The placeholders in memory get replaced by real values — then .gitignore is never created for .env.

The file that ships is named like a dev file. .env.txt, env.local, .env.development — these often bypass the .gitignore pattern *.env because the name is subtly different.

History keeps the key after the file is deleted. Deleting .env in a new commit is not a fix. The key stays in every previous commit unless you rewrite history.

Paste this into supabase.com/dashboard → your project → SQL Editor. It shows every object a service_role (or anon) key can reach that your RLS policies do not actually protect:

select n.nspname, c.relname, c.relrowsecurity
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where c.relkind in ('r', 'p')
  and n.nspname = 'public'
  and not c.relrowsecurity
order by n.nspname, c.relname;

Every row of that result is readable and writable by anyone holding the public anon key that ships in your browser bundle. If relrowsecurity is false, Row-Level Security is not even on for that table.

For git: git log --all --oneline -- .env shows every commit the file touched. If you see more than the one "deleting it" commit, the key is still in history.

git filter-repo or BFG)..env, create .gitignore entry *.env* before first launch." Every check in that list — RLS coverage, open policies, USING (true) traps, write-without-read policy conflicts, and the git-history secret scan — I've packaged as a free, read-only, 60-point pre-launch check that runs against your own DB in about 30 seconds and uploads nothing:

github.com/cekuu35/supabase-rls-leak-demo

The scan behind this post ran the same evidence standard: decode the JWT, confirm role == "service_role", confirm the project is live. No data was read, no exports were made, nothing was saved. If you want a second pair of eyes on your schema after rotating — policy conflicts, unisolated joins, service_role exposure paths — that is the read-only review I do as paid work, and the email + Gumroad link are in my profile.

── more in #ai-tools 4 stories · sorted by recency
── more on @supabase 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/58-of-154-public-sup…] indexed:0 read:3min 2026-09-24 ·