A Supabase anon key in the browser is not the breach
Developers often panic when they find a Supabase anon key in browser code. That key is meant to be public. The real question is what the anon role can do after the key is copied—and whether a privileged key was exposed instead.
A Supabase publishable key or legacy anon key is safe to include in public client code. It identifies the project and gives the request the public role; Postgres grants and Row Level Security still decide which tables, operations, and rows are available.
A secret or legacy service-role key is different. It belongs only in trusted backend code and can bypass RLS. If a privileged key appears in a browser bundle, disable or rotate it, remove the client-side copy, and review the API and Postgres logs for its use.
Why the anon key is visible
A browser must send a project key to call Supabase, so a visitor can copy it from the JavaScript bundle or network panel. Supabase's API key documentation describes publishable keys as safe for public components. The legacy anon key serves the same client-side role. Neither should be treated as a password.
The key is public; the permissions must be narrow
A copied public key lets an attacker behave like any other signed-out visitor. That is safe only when the anon role has narrow grants and every exposed table has a correct RLS policy. If your product has a public catalogue, anonymous reads may be intentional. Anonymous reads of invoices, profiles, or private files are not.
- Expected: the public key appears in browser code and can read deliberately public data.
- Risky: the anon role keeps insert, update, or delete grants the product does not use.
- Exposed: a table in an API schema has useful grants but RLS is missing or too broad.
- Critical: a secret or service-role key is shipped to the browser and bypasses RLS.
Test what an attacker can do with the public key
Do not test with an owner account or a privileged server client. Open a signed-out session and call every public table, view, function, Storage bucket, and Edge Function your frontend knows about. Then repeat as an ordinary user from another tenant. The negative result—data not returned—is the security test that matters.
# Use the same public key a browser receives.
curl 'https://PROJECT.supabase.co/rest/v1/private_table?select=*' -H 'apikey: YOUR_PUBLISHABLE_OR_ANON_KEY'
# A secure response is an authorization failure or no rows,
# depending on the grants and RLS policy you intentionally chose.If a privileged key was exposed
- Disable or rotate the key first. Removing it from source code does not remove copies already downloaded.
- Remove it from public environments. Check browser-prefixed variables, build output, deployment settings, logs, and documentation.
- Review activity. Search API and Postgres logs for the privileged role, unusual origins, bulk reads, writes, and function calls.
- Repair the architecture. Move the privileged operation behind an authenticated server or Edge Function with narrow input validation.
- Add monitoring. Alert when privileged traffic appears from a browser context or behaves unlike the normal server workload.
How Defencecore helps after deployment
A source-code scan can find a key before release. Defencecore covers the production side. It reads Supabase API, Postgres, Auth, Storage, Realtime, and Edge Function logs and checks them continuously. If a privileged request appears where browser traffic should be public-only, the incident explains the role, source, affected route, and first containment step.
Continue with the complete guides to Supabase RLS setup and Supabase API security.
Frequently asked questions
- Is the Supabase anon key safe to expose?
- Yes. The legacy anon key and newer publishable keys are intended for public applications such as browsers and mobile apps. They identify the Supabase project but do not replace authorization. Postgres grants and Row Level Security determine what a request using the key can read or change.
- What can someone do with my Supabase anon key?
- They can make the same signed-out API calls your application can make. If the anon role can read a public table, they can read it. If a table has broad grants and missing or weak RLS, the key makes that mistake reachable. A correctly configured project should remain secure even when the key and project URL are known.
- Which Supabase key must never be exposed?
- A secret key or legacy service_role key must stay in trusted backend components. These keys provide elevated database access and can bypass Row Level Security. If one reaches a browser bundle, rotate or disable it immediately and review what it accessed.
- Can Defencecore detect a leaked Supabase key?
- Defencecore can detect runtime signs of privileged-key misuse, such as a service-role request arriving with a browser user-agent or website Origin header. It also watches for related behavior such as bulk reads and RLS changes. It cannot scan every source repository or guarantee that an unused leaked key will appear in logs.