If a Supabase secret key or legacy service_role key is confirmed public, treat it as compromised. Fix the exposure path, create a replacement secret key, update the trusted backend components that need it, verify the rollout, and delete or deactivate the compromised credential. Do not put the replacement into the same client bundle or repository.
Do not follow this runbook for a publishable or legacy anon key merely because it appears in JavaScript. Those client keys are designed to be public.
First, confirm which key was exposed
| Evidence | Classification | Response |
|---|---|---|
sb_publishable_... in browser code | Current publishable key | Expected public configuration; review RLS instead of rotating for visibility alone |
Dashboard confirms legacy anon key | Legacy public client key | Expected public configuration; plan migration, but visibility alone is not a compromise |
sb_secret_... in a public location | Current privileged key | Confirmed exposure; contain and replace |
Dashboard confirms legacy service_role key in a public location | Legacy privileged key | Confirmed exposure; replace with a current secret key |
JWT-shaped eyJ... with no owner-side role evidence | Unknown | Needs verification; do not guess and do not use the value |
Supabase’s current API-key documentation states that secret and service_role keys provide elevated access through the built-in service_role Postgres role, which bypasses Row Level Security. The current secret-key format adds browser-use blocking, but that is not containment: an attacker can use a leaked key outside a browser.
The containment sequence
1. Record the facts without copying the secret
Capture:
- where the key appeared;
- when that artifact first became public, if known;
- which deployment, repository, log, image, package, or message contained it;
- which backend components legitimately use the credential;
- whether the value is a current secret key or legacy
service_rolekey.
Store only a redacted identifier, such as the key name and a short prefix. Do not paste the full value into the incident ticket, chat, or a screenshot.
2. Fix the exposure path before distributing a replacement
Examples include:
- a client-prefixed environment variable such as
VITE_...orNEXT_PUBLIC_...; - a shared module imported by both server and client code;
- a committed
.envfile or generated configuration file; - build logs, application logs, support messages, or screenshots;
- a container image, package, source map, or deployment artifact available to untrusted users.
Removing the visible string from the latest source commit is not enough when the value remains in Git history, a cached JavaScript asset, an old deployment, a published package, or a copied log.
3. Create a new secret key
For a current sb_secret_... key, Supabase instructs owners to create a new secret key in Settings → API Keys. Use a distinct key name for the backend component where practical.
If the exposed credential is a legacy JWT-based service_role key, Supabase’s current guidance is to replace it with a new secret key rather than trying to create another legacy key. The migration guide maps service_role to secret keys and explains the compatibility differences.
Store the new value in the hosting provider’s secret manager or another trusted server-side secret store.
4. Deploy the replacement to trusted components
Inventory every legitimate consumer:
- API servers and serverless functions;
- background workers and scheduled jobs;
- Edge Functions;
- CI/CD tasks;
- database webhooks or
pg_netcalls; - third-party integrations.
Update one component at a time where the architecture permits it. Verify normal server-side operations and watch for authentication failures. Do not leave the old key active indefinitely as a fallback.
New publishable and secret keys are not JWTs. Supabase documents header and Edge Function compatibility differences, so test the actual integration rather than assuming the value is a drop-in replacement everywhere.
5. Delete or deactivate the compromised credential
After legitimate components use the replacement, delete the compromised current secret key. Supabase notes that deletion is irreversible.
For legacy keys, follow the dashboard’s migration and deactivation flow. Deactivating legacy keys can be reversible, but the legacy anon and service_role pair has coupling to the old JWT-secret system. Review Supabase’s JWT signing-key guidance before changing that system during an incident.
If there is evidence of active abuse, containment speed may matter more than a zero-downtime transition. That is an incident-specific decision: identify critical services, revoke access, and restore them with the new key under an explicit response plan.
Remove the exposed copies
Credential revocation is the security boundary; cleanup reduces rediscovery and accidental reuse.
- Rebuild the frontend without the key.
- Purge or age out CDN assets that contain it.
- Remove public logs, packages, images, snippets, and attachments where possible.
- Rewrite repository history only when you understand the collaboration and deployment impact.
- Check forks and mirrors you control.
- Invalidate build caches that can reproduce the old artifact.
Never delay revocation because complete internet cleanup is impossible. Once public, a key must be considered copied.
Review what happened during the exposure window
The key’s RLS-bypassing role makes impact review a separate task from rotation.
Use owner-accessible platform and application logs to look for:
- unexpected database reads or writes;
- user or admin operations outside normal application behavior;
- unusual request sources, times, volumes, or table access;
- creation of new privileged data or modification of roles and ownership fields;
- export, storage, or authentication activity associated with the affected backend path.
The absence of an obvious log entry does not prove the key was unused. Record available log coverage, retention, and blind spots. If personal or regulated data may have been accessed, involve the people responsible for legal, privacy, contractual, and customer-notification decisions.
Prevent the same exposure
- Use publishable keys in public clients and a separate secret key per backend component where practical.
- Keep server clients in explicitly server-only modules.
- Allowlist client-exposed environment-variable names instead of broadly exporting configuration.
- Scan source, build output, packages, and source maps before deployment.
- Reject privileged key patterns in pre-commit and CI checks.
- Avoid logging authorization headers, environment dumps, and full configuration objects.
- Practice secret rotation before an incident.
- Review RLS even when no service key is exposed; publishable-key safety depends on the policy boundary.
What the free scan can tell you
The free scan can identify a privileged-looking pattern in the submitted page’s referenced public assets, redact its location, and mark it Needs verification when public evidence cannot establish the role. It does not use the key to determine whether it works.
Owner-side dashboard confirmation can change that state to Confirmed. A public scanner should never call Supabase with a discovered credential.
When a Human security review is appropriate
Rotation closes the credential path. It does not answer whether the credential was used, whether other privileged values followed the same path, or whether the affected application allowed cross-tenant changes before or after containment.
A scoped review can trace the build boundary, inspect authorization and RLS logic, review the highest-risk logs available, and define retest evidence. It is not a substitute for a formal incident-response, forensics, privacy, or legal engagement when those are required.
Limitations
This is a technical containment checklist, not a universal incident-response plan. Supabase key and signing-key flows change over time; use the current dashboard and provider documentation during the incident. Do not rotate a visible publishable or anon key solely because it is public.
Revision history
- 2026-07-27: Initial draft using Supabase’s current secret-key replacement, legacy migration, and signing-key guidance.