Anyone can open dev tools on your live app and read every key in your JavaScript. That is not a bug; that is how the web works. What matters is whether the keys sitting there are the kind designed to be public, and whether the database behind them is configured to assume they are.
Is it safe to expose your Supabase anon or publishable key?
Yes — conditionally, and the condition is the whole answer. Supabase’s own API key documentation describes publishable keys as “Safe to expose online: web page, mobile or desktop app, GitHub actions, CLIs, source code.” Supabase now explains the boundary this way: “Every key resolves to a built-in Postgres role, and that role is what your Row Level Security policies match on.”
Which means the key is not the security boundary — row-level security is. Supabase’s deployment instruction is direct: “Row Level Security decides what this client can reach, so enable it on every table before you deploy.” An app with a publishable key in the bundle and RLS off on one table has not exposed a key; it has published that table. (Source: Supabase, “API Keys”, retrieved 10 September 2026.)
Is it safe to expose the Supabase service_role or secret key?
No. Never, under any circumstance, in any bundle, in any public repository. Supabase documents the secret key as being for “backend components of your app” only, because these keys “provide full access to your project’s data, bypassing Row Level Security.” The service_role Postgres role carries the BYPASSRLS attribute, so every policy you wrote is skipped for anyone holding that key.
A leaked secret key is not a severity-medium finding to schedule for next sprint. It is read, write and delete on every row you have, for anyone who viewed source. If one is in your bundle right now, the sequence is: rotate the key in the Supabase dashboard first, then move the call that needed it to a server route or edge function, then redeploy. Rotating first is what stops the bleeding; the refactor can take as long as it takes.
Supabase is replacing anon and service_role — the deadline is the end of 2026
Supabase has introduced a new key format: publishable keys prefixed sb_publishable_ and secret keys prefixed sb_secret_, replacing the legacy JWT-based anon and service_role keys. On the legacy pair, the documentation is explicit: “Supabase is deprecating the anon and service_role keys by the end of 2026. Use the publishable (sb_publishable_xxx) and secret (sb_secret_xxx) keys instead.” It still names no exact date, so “the end of 2026” is the whole of the deadline Supabase has published.
The practical consequence for anyone auditing an app in 2026 is that both formats are in the wild at once, and a scanner or a checklist that only knows the old JWT shape will walk straight past an sb_secret_ key sitting in a client bundle. If you are checking your own app by hand, search for both. (Source: Supabase, “API Keys”, retrieved 6 September 2026. Supabase reworded this sentence between 12 August and 6 September 2026. The deadline it names is unchanged, the sentence carrying it is not, and this page quotes the current one.)
Which keys are safe in a browser bundle, and which are a breach
- Supabase
sb_publishable_(and legacyanon). Safe to ship to the browser — that is what it is for — provided row-level security is enabled and correct on every table holding user data. - Supabase
sb_secret_(and legacyservice_role). Never. Bypasses RLS entirely. Server-side only. - Stripe publishable key (
pk_). Safe. It is designed to be read by the browser and can only create payment intents and tokens, not read your account. - Stripe secret key (
sk_). Never. It can move money and read every customer record. - Anthropic, OpenAI and other model-provider keys. Never. There is no publishable variant. A key in the bundle is a metered account anyone can spend against; the call has to go through a route you own.
- Email, storage and webhook signing secrets. Never. None of these have a public tier, and a signing secret in the client defeats the point of signing.
How to detect an exposed API key in your own app
The manual version takes about two minutes and requires no tooling. Open your live app, open dev tools, go to the Sources panel, and search across all loaded files for sb_secret_, service_role, sk_, and the literal word secret. Then check your network tab for any request that carries an Authorization or apikey header your app did not obviously need. Anything you find in there, a stranger can find in there.
The limit of the manual version is coverage: keys hide in lazily-loaded chunks that only download on a route you did not click, in inlined environment objects, and in source maps you did not mean to publish. BreachProbe fetches every script your app serves and reads them the way an attacker would, and it names the specific key type it found rather than telling you that “a secret was detected.” That part is free.
An exposed publishable key is only as safe as your RLS
This is where the two halves meet. A publishable key is safe because RLS is doing the work — so if RLS is off, or on but written wrong, the key you were told to publish becomes the front door. That combination has a CVE attached to it. NVD carries CVE-2025-48757, published 29 May 2025, as “an insufficient database Row-Level Security policy in Lovable through 2025-04-15 allows remote unauthenticated attackers to read or write to arbitrary database tables of generated sites.” Two things about that record are worth stating precisely rather than leaning on. The 9.3 CRITICAL score is a secondary CVSS 3.1 metric supplied by the CNA, cve@mitre.org — NVD has not published a primary score of its own, and as of today the entry’s status reads Deferred, meaning NVD does not plan to enrich it further. And Lovable disputes the entry outright, arguing that individual customers are responsible for protecting their application data — which, whatever you make of it as a defence, is a fair statement of whose job the check is. Cite it for what it is: a disputed, CNA-scored record that describes this exact failure mode, not an authoritative severity rating. (Source: NVD, CVE-2025-48757, retrieved 12 August 2026.)
So the key audit is half a job on its own. Pair it with the RLS audit, which covers the harder question of whether a policy that exists actually isolates one user from another, and with the nine-check launch list for everything either one misses.
Check both at once
Paste your URL into BreachProbe and the free scan reads your served JavaScript for exposed keys in both the legacy and the sb_ formats, and lists the database tables answering to an anonymous request. The full report then signs up two throwaway users through your own app and proves whether one can read the other’s rows — the test that decides whether your publishable key is safe to publish. If it comes back bad and you would rather not fix it yourself, the report qualifies you for a developer who does this for a living.