Supabase API Key Exposed? Check Which Key It Is
A Supabase key in frontend code is not automatically a leak. Publishable keys, and legacy anon keys, are designed for public clients and rely on grants plus Row Level Security. Secret keys and legacy service_role keys are privileged, bypass RLS, and must remain in server-controlled code.
Scan Your Supabase AppHow It Happens
Supabase now recommends publishable keys for browsers, mobile apps, CLIs, and other public components. Older projects may still use the legacy anon JWT key for the same role. Both are expected to be visible and only reach data allowed to the anon or authenticated Postgres role. The dangerous mistake is putting an sb_secret_ key or legacy service_role JWT into code sent to a user. Those keys map to service_role and bypass RLS. This often happens when a query is blocked by a policy and someone swaps in a privileged key to make it work instead of fixing the policy. Public prefixes make the leak permanent in a build. A value named NEXT_PUBLIC_SUPABASE_SECRET_KEY, VITE_SUPABASE_SERVICE_ROLE_KEY, or similar will be bundled into browser JavaScript even when it came from a private deployment setting.
Impact
An exposed secret or service_role key lets an attacker use the Data API with elevated access that bypasses Row Level Security. Depending on existing table grants and enabled services, they may be able to read, insert, update, or delete protected rows and access privileged Storage or Auth operations. A publishable or anon key has a different risk model. It is not confidential, but it makes weak grants and RLS policies directly exploitable. The right response is to test authorization, not to hide the public key. Removing a privileged key from the frontend is not enough. Anyone who copied it can keep using it until it is disabled or rotated, and every legitimate server that used it must be updated.
How to Detect
Search source files, generated browser bundles, deployment variables, logs, and Git history for sb_secret_, SUPABASE_SECRET_KEY, SUPABASE_SERVICE_ROLE_KEY, or legacy JWTs whose payload role is service_role. Any of those in browser-delivered code is a critical leak. Treat sb_publishable_ and legacy anon keys as public identifiers, then test what anon and authenticated users can actually do. Review table grants before RLS policies because Postgres evaluates grants first. Vibe App Scanner inspects deployed client code, classifies Supabase keys, and probes reachable tables, Storage, RPC functions, and authentication configuration.
How to Fix
If a secret or service_role key reached a browser or public repository, disable or rotate it immediately in Settings > API Keys, update every legitimate server consumer, and verify the old key no longer works. Removing it from the latest commit does not invalidate copies or erase Git history. Use an sb_publishable_ key in new frontend code. A legacy anon key can remain public during migration, but Supabase plans to deprecate legacy anon and service_role keys by the end of 2026. Keep sb_secret_ and legacy service_role keys in server-controlled components only, such as protected backend services or Edge Functions. Elevated code must perform its own authorization because RLS will not protect requests made with those keys. Finally, test grants and RLS for anon and authenticated roles. A public key is only safe when the permissions behind it are safe.
Code Examples
Supabase client initialization
// DANGEROUS: privileged key compiled into the browser
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_SECRET_KEY!
)// Browser: publishable key is designed to be public
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
// Server only: never expose this client to the browser
const adminClient = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SECRET_KEY!
)Frequently Asked Questions
Is it safe to expose a Supabase publishable or anon key?
Yes, those keys are designed for public clients. They do not make your data safe by themselves. Table grants and RLS policies must still restrict the anon and authenticated roles to exactly the operations and rows your app intends.
What is the difference between Supabase publishable, secret, anon, and service_role keys?
Publishable keys are the current public-client keys, while secret keys are the current privileged server keys. Anon and service_role are the legacy JWT equivalents. Supabase says the legacy keys are deprecated through the end of 2026, so new code should prefer publishable and secret keys.
How do I respond to an exposed secret or service_role key?
Disable or rotate it in Settings > API Keys, replace it in all legitimate server environments, confirm the old key fails, and remove it from code and Git history. Also review logs and data for unauthorized use during the exposure window.
Can an attacker find a removed key in Git history?
Yes. Git preserves earlier commits. Removing the current line does not revoke the credential or remove old copies, so rotate the key and then purge it from repository history where appropriate.
Related Security Resources
Explore Related Resources
Is Your App Vulnerable?
vas automatically scans for exposed api keys and other security issues in Supabase apps. Get actionable results with step-by-step fixes.
Your first scan is free: see your security score and every issue count in minutes, then unlock those step-by-step fixes from $19/month.