Dev.to Security 🔐 Cybersecurity 👁 0 📖 3 min read

I re-verified 30 disclosed Supabase keys. 20% were still live.

I re-verified 30 disclosed Supabase keys. 20% were still live. The uncomfortable finding: developers who thank you for reporting a leaked key — and swear they rotated it — often don't. by Cenk Kurtoglu — I audit Supab

I re-verified 30 disclosed Supabase keys. 20% were still live.

The uncomfortable finding: developers who thank you for reporting a leaked key — and swear they rotated it — often don't.

by Cenk Kurtoglu — I audit Supabase/Postgres access control for a living (github.com/cekuu35)

The setup

Over the last two months I've disclosed dozens of committed Supabase service_role keys to maintainers. The workflow: find a committed key, verify it's live, email the owner with a 2-minute fix, move on. Most replies are warm: "Wow, thank you so much — I'll get that rotated immediately."

That "immediately" kept nagging at me. What does it actually mean?

So this week I ran a systematic re-verification pass: went back through my disclosure history and re-tested every project — fresh key extraction, fresh JWT decode, fresh live check against each project's REST endpoint (a single authenticated ping, no data reads, no logins).

The numbers

Out of 30 previously-disclosed repos:

State Count What it means
Key still committed AND still live (HTTP 200) 6 The database is readable/writable by anyone who finds the repo — right now
Key committed, project dead (endpoint paused/deleted) 14 Exposure inactive, but the key wakes up if the project is ever restored
Actually rotated and clean 12 The fix worked

One in five "fixed" projects still had a working master key sitting in public code.

The pattern that worries me

The worst case isn't the silence. It's this exact sequence, which happened twice this week:

  1. I report a live service_role key in a committed file.
  2. The owner replies: "Wow, thank you — I'll get that rotated and removed immediately."
  3. Days later I re-verify: the same key, same file, still HTTP 200.

The rotation either never happened or happened to the wrong key — and the owner believes they're safe. That false confidence is more dangerous than never replying, because nobody re-checks.

One key I re-verified was issued in May — reported in October, "fixed" two days before my re-check, still live at verification time.

Why rotation fails (the ones I've seen)

  • The dashboard flow confuses "rotate service key" with "regenerate anon key." Both buttons look similar; only one invalidates the leaked credential.
  • The key lives in more than one place. They remove it from .env, forget wrangler.jsonc, .env.backup, the MCP config, the README setup section. The app keeps working — because the app still reads the old key from somewhere else — so it feels fixed.
  • Git history is treated as cleanup. Deleting the file from HEAD doesn't remove the key from history. That's fine only after rotation — but people do it in the wrong order and skip rotation entirely.

The 3-step check that would have caught all six

  1. Decode the committed JWT. The payload tells you role and ref in two seconds. role: service_role + repo public = emergency.
  2. Ping, don't assume. One authenticated GET to https://<ref>.supabase.co/rest/v1/ with the key as both apikey and Authorization: Bearer. 200 means the key is alive. 401 means rotation worked. Nothing else matters.
  3. Rotate first, clean later. Rotate the JWT secret in the dashboard (invalidates the old key instantly), then update every location and commit. In that order, git history becomes harmless.

What I'm doing with this

I now offer rotation verification as a fixed-scope service: I re-test every key I've ever reported for you and hand you a two-line verdict — live or dead — with evidence. It's the difference between "I think I rotated" and "it's dead, here's the 401."

If you've ever committed a Supabase key: run step 2 above right now. It's one request. If you get a 200, rotate — the dashboard takes two minutes and the alternative is a stranger with full read/write on your database.

Cenk Kurtoglu — cenkkurtoglu.com · github.com/cekuu35. I disclose leaked keys for free, permanently — no payment required for the report itself.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.