VibeGuard
Guides

Detect a service_role key in your client bundle

The service_role key carries BYPASSRLS. Every policy you have written is decorative to anyone holding it. Once it is in a bundle served to browsers it is public, and no amount of RLS work matters until it is rotated.

This happens most often when an AI tool needs an admin operation, finds the service key in the environment, and wires it into client code because that is where the call was being written.

Rules that check this

How the check works

VibeGuard fetches your deployed page, follows the same-origin script tags and module preloads, and scans the bundles for Supabase credential formats: legacy JWTs, `sb_secret_*`, `sb_publishable_*` and management tokens `sbp_*`.

A JWT is classified by decoding its payload and reading the `role` claim — unverified, deliberately, because the question is what the key claims to be, not whether the signature is good.

The key is never stored

A finding records a fingerprint — the first six characters and a length — never the key. Recording a live RLS-bypassing credential in our database, then rendering it in a dashboard, would make the leak worse.

What to do when you find one

Rotate it first, in the Supabase dashboard under Settings → API. Everything using the old key stops working, which is the point: you need that list.

Then move whatever needed it behind a server route, a Next.js Route Handler, or an edge function. If the operation genuinely needs to bypass RLS, it does not belong in code you ship to browsers.

Frequently asked

Do you need access to my repository?
No. The check reads your deployed site the way any visitor can. No GitHub access and no signup.
What if my config loads at runtime?
Then the bundle scan finds nothing and the report says so. Paste your project URL and anon key directly and the table checks still run.
Is the scan safe to run against production?
It only issues GET, HEAD and OPTIONS. There is no code path that can write, and loopback and private address ranges are refused before the socket opens.

Check your project in about ten seconds

Paste a URL. No signup, no writes, nothing stored.

Run the free audit
supabase service_role key leaksupabase service_role key in client bundlebolt.new supabase service_role exposeddetect service_role key exposure in Next.js