← Blog · Published Oct 18, 2026 · Updated Oct 20, 2026 · by the Vibefixr team

Leaked your Supabase service_role key in a vibe-coded app? What to do now

Supabase gives every project two kinds of keys. One is meant to be public. The other is the master key to your database. Vibe-coded apps mix them up more often than you’d think, usually when an AI assistant “fixes” an RLS error by swapping in the key that makes the error go away.

Not sure whether your live app ships a secret key? Check your app now with our free Supabase key checker. It only reads your public JavaScript and never uses a key it finds.

The two kinds of keys

KeyLooks likeWhere it belongs
Publishable key (legacy: anon)sb_publishable_… or a long JWT starting with eyJAnywhere: browser, mobile app, public repo. Your RLS policies decide what it can reach.
Secret key (legacy: service_role)sb_secret_… or a long JWT starting with eyJOnly servers, Edge Functions and jobs you control

The secret keys map to the service_role Postgres role, which has the BYPASSRLS attribute. In Supabase’s API key docs, it’s the master key: every Row Level Security policy you wrote is skipped. Anyone who has it can read, change or delete every row in every table the Data API exposes, and impersonate your backend.

Because both legacy keys are JWTs that start with eyJ, they look identical at a glance. The difference is inside: the decoded payload contains "role":"anon" or "role":"service_role".

How it ends up in public

How to check your live app

Open your site, open DevTools (F12), go to Sources or Network and search the loaded JavaScript for sb_secret_ and service_role. For eyJ… strings, you can decode the middle section (it’s base64) locally to see the role. Don’t paste a suspected secret key into random online decoders. Or run our free app health check, which scans your public bundles for this pattern without ever showing the full key.

Also search your repository, including history, for the same strings. GitHub’s secret scanning may already have flagged it if the repo is public.

Not sure which of these is your problem? The free health check looks at your live app in seconds, or request a free scan and we’ll tell you what we find.

If you found it: the order matters

Supabase’s own advice for a leaked key starts with something counterintuitive: don’t rush. Fix the root cause before you rotate, or the new key leaks the same way on the next deploy. Their documented sequence, in short:

  1. Remove the cause. Take the key out of frontend code and public env vars. Anything that genuinely needs elevated access must move to a server or Edge Function.
  2. Create a new secret key in the Dashboard under Settings → API Keys. If the leaked one was a legacy service_role JWT, replace it with a new sb_secret_ key.
  3. Replace the old key everywhere it’s legitimately used, then confirm every component runs on the new one.
  4. Retire the leaked key. Secret keys are deleted (irreversible, so do it after step 3). Legacy JWT keys are deactivated, which is reversible if you find a client you missed.

Supabase is deprecating the legacy anon and service_role keys by the end of 2026, so this is a good moment to move to publishable and secret keys anyway. One useful safety net: Supabase says the new secret keys return 401 when used from a browser. That stops the accidental case, but not an attacker with curl, so it’s no substitute for keeping the key private.

Then assume it was used

Rotating stops future abuse. It doesn’t undo anything that already happened. If the key was public for a while, check:

If personal data may have been read and you have users in the EU, you may have notification duties under GDPR. That’s a question for a lawyer, not a blog post, but don’t ignore it.

Why the “quick fix” caused it in the first place

The usual story: a query returns an empty array or 42501, the AI suggests the service key, and everything works. What actually happened is that the security check was removed instead of satisfied. The real fix is correct grants and RLS policies (see empty array and 42501 on new tables), plus moving truly privileged operations to the server.

Checklist

Stuck? Get a free scan of your app

Send us your repo and a one-line description of what’s broken. We’ll email you the top issues we find and why they matter. If you’d rather not touch it yourself, the $199 Fix covers up to 5 issues, delivered as a pull request with tests — not fixed, full refund.

Get a free scanRun the free health check

FAQ

What can someone do with my Supabase service_role key?

It skips every Row Level Security policy. Anyone who has it can read, change or delete every row in every table the Data API exposes.

How do I tell the anon key from the service_role key?

New keys start with sb_publishable_ or sb_secret_. Legacy keys are both JWTs starting with eyJ; the decoded payload says "role":"anon" or "role":"service_role".

Should I rotate the key immediately?

Supabase advises removing the root cause first, so the new key doesn’t leak the same way on the next deploy. Then create a new secret key, switch everything over, and retire the old one.

Is rotating the key enough?

No. Rotating stops future abuse but doesn’t undo anything already done. Review sensitive tables, users, storage and logs for signs of misuse.

Related guides

Launching soon? Run through our launch checklist for AI-built apps: 14 checks, each linked to the full guide.

Information here is checked against official docs at the time of writing. Platforms change, so verify against the linked sources.