Web & SoftwareUpdated 11 min read

Is Your Lovable App Exposing the Supabase service_role Key?

If a Lovable or Vite app shipped the Supabase service_role or secret key in the browser bundle, treat every customer row as readable. Check in five minutes, rotate first, then harden.

Founder at a laptop in natural window light reviewing a live app, no readable screen data
If the admin key is in the bundle, RLS does not matter. Check the live JavaScript, then rotate.

For SaaS / AI SaaS Founders · Beginner · Commercial · Solves: Does not know if the admin key is in the browser, Afraid customer data is already exposed, Confused by RLS vs a leaked service_role key, Considering a panic rewrite

Key takeaways

  • A service_role or secret key in the Vite client bypasses RLS.
  • Search the live bundle for service_role, sb_secret_, and eyJ.
  • New secret keys return 401 in Chrome and still work from curl.
  • Rotate the leaked key before you keep shipping features.
  • Hire for a hardening pass, not a redesign or a panic rewrite.

You do not have a Row Level Security problem yet. You may have a worse one. The admin key that bypasses every policy may already be sitting in the JavaScript your visitors download.

That is the search behind is the Supabase service_role key visible in Lovable apps, and the cousin queries: Lovable API key exposure, VITE_SUPABASE_SERVICE_ROLE_KEY, secret key in the frontend bundle.

The people typing those phrases are usually not security engineers. They are founders who shipped a Lovable, Bolt, v0, or Cursor MVP, connected Supabase because the chat said to, and then saw a Reddit thread or a scanner warning. They want a yes or no. Then they want to know whether they just exposed every customer row.

This is not the same problem as missing RLS

I already wrote where vibe-coded SaaS gets dangerous when RLS is missing. That article is about the public key. The publishable or anon key is supposed to be in the browser. It is safe only if every table has RLS, grants, and policies you have actually tested as a second user.

A leaked service_role or secret key makes those policies irrelevant. The key maps to the Postgres service_role, which has the BYPASSRLS attribute. Policies never apply. Anyone who can present the key can read and write the tables the role can reach.

Supabase's own API keys guide is blunt: use a publishable key anywhere you ship code, and a secret key only on a server, Edge Function, or cron job you control. The building metaphor they use is the right one. The publishable key is taped to the front door and only opens the lobby. The secret key is the master key. It stays in your pocket.

Why Lovable and Vite make this leak so common

Lovable compiles the frontend with Vite. Vite's env docs say any variable prefixed with VITE_ is statically replaced into client source at build time. That is documented behavior, not a bug. VITE_SOME_KEY becomes a string in the bundle. DB_PASSWORD without the prefix does not.

Lovable's Secrets documentation draws the same line. Secrets are for Edge Functions and server-side integrations. VITE_ values belong in .env and are embedded in the client. VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY are supposed to be public. A service_role or secret key is not.

The failure is mechanical. A founder, or the model, needs an admin write from a React hook. Someone adds VITE_SUPABASE_SERVICE_ROLE_KEY, or pastes the long eyJ JWT into createClient on the client. The preview works. The dashboard writes work. The build succeeds. The key lands inside assets/index-*.js as a string literal.

Lovable's security checklist already says the frontend is always public, secrets must not live there, and auth, payments, and validation belong in Edge Functions. The leak happens when the generated app ignores that split because the chat found a faster path.

How to know in five minutes

You do not need a pentest. You need the live URL and Chrome DevTools.

1. Open the published app, not only the Lovable preview editor.

2. Open DevTools. Go to Sources. Search the page (Ctrl-F or Cmd-F across files) for service_role, sb_secret_, VITE_SUPABASE_SERVICE, and eyJ. Legacy service_role keys are long JWTs that start with eyJ. New secret keys look like sb_secret_.

3. Check Network. Filter for supabase.co or your project ref. Look at the apikey header. If it is the JWT or sb_secret_ value, the client is presenting the privileged key.

4. Open the project .env and Secrets panel. A VITE_ name next to a service_role or secret value is already a fail. Lovable will reject a VITE_ name inside Secrets, which is correct. The damage happens when the same value is committed in .env instead.

5. In the Supabase dashboard, open Settings, then API Keys. Note whether the project still relies on legacy anon and service_role keys. Supabase is deprecating those JWT keys by the end of 2026 in favor of publishable (sb_publishable_) and secret (sb_secret_) keys. Both systems can be live at once. Creating the new keys does not revoke the old ones.

Legacy JWT vs the new secret key

What each leaked key can do from a stranger's laptop
Key in the bundleWhat it looks likeFrom ChromeFrom curl or a script
Legacy service_role JWTLong token starting with eyJWorks. Full BYPASSRLS.Works. Full BYPASSRLS.
New secret keysb_secret_...Supabase returns HTTP 401 by matching User-Agent.Works unless you delete the key. Browser block is not enough.
Publishable or anon keysb_publishable_... or a different eyJ JWTExpected. RLS and grants decide the rest.Same. This is the public door key.

Do not celebrate a 401 in the browser and stop. Supabase's leaked-key procedure says the browser block is not a fix. An attacker who copied sb_secret_ can still call your project from a tool that does not look like a browser. Delete the leaked key after every consumer has moved to a new one.

What this actually costs you

This is not a code-quality nit. It is a customer-data problem.

If the key is in the bundle, a stranger can list emails, reset another user's workspace, export uploaded files, or rewrite subscription state. If you also store Stripe customer IDs or raw PII in Postgres, they can take that too. Your RLS policies will not save you. The role never reads them.

That is why this sits next to why Lovable apps break when real users show up and why live Stripe fails after test mode. Preview hides the blast radius. The first 20 strangers expand it.

If paying customers already exist, treat this as an incident. You do not need me to invent a horror story. The official docs already describe the permission model. The commercial question is whether you keep shipping features on top of an open admin door.

Rotate first. Then change the architecture.

Supabase's leaked-key procedure is the order. Fix the root cause before you rotate, then create a new secret key, replace it everywhere, confirm every consumer moved, and only then delete or deactivate the old one. Deleting a secret key cannot be undone. Deactivating a legacy service_role key is reversible if you missed a worker.

The architecture fix is not a rewrite. The client keeps the publishable or anon key. Privileged work moves to a Supabase Edge Function. Lovable already injects SUPABASE_SERVICE_ROLE_KEY into that runtime. The frontend calls the function with the user JWT. The function checks the user, then does the admin write. The key never returns to the browser.

Then do the RLS job. Enable it on every table. Write policies for anon and authenticated. Run a deny test as a second user. A leaked admin key and an open table are two different ways to lose the same data. You can have both at once.

When a founder should stop prompting and hire

If the key is in the bundle and you already have users, stop adding features. When to hire a developer to productionize a Lovable app still holds: hire when a trust boundary can hurt users or money. An admin key in the client is that boundary.

Do not buy a redesign. Do not buy a Next.js rewrite because the tweet said Vite is unsafe. Vite is doing what it is documented to do. Buy a scoped hardening pass: rotate, remove the key from the client, put admin writes in Edge Functions, prove RLS with a deny test, and make sure the company owns GitHub and the Supabase project. What that pass should cost is a different article. This one is the incident.

My take

Vibe coding is legitimate. Shipping before you validate is also legitimate. Putting the master key in the file the browser downloads is not a vibe. It is a category error the model will happily repeat because the admin write works on the first try.

The useful human job here is not prettier React. It is deciding what must never reach the client, then proving it. Founders who stay in the chat after a leaked service_role key are optimizing the lobby while the master key is taped to the glass.

If you found the key, rotate today. If you cannot tell whether you found it, that is already a hiring signal.

Related services

Work this article points to.

Digital strategy

Digital strategy

Most teams do not need another workshop deck. They need a digital strategist who can say what the site is for, what to build first, and what can wait. I do digital strategy consulting that stays connected to design and website development, so the plan does not die in a PDF.

View service
Website redesign

Website redesign

A redesign fails when it starts in Figma. Website redesign services should start with website strategy, the pages that create pipeline, then website design and website development. I run that sequence so a custom website redesign does not erase the rankings you already have.

View service

Sources & references

Related links

Zlatko Marjanovic — founder of ZedNova Studios

Zlatko Marjanovic

Founder, ZedNova Studios

I am Zlatko Marjanovic, founder of ZedNova Studios and an AI product engineer. I take over Next.js, Supabase, and Stripe codebases, fix what is actually broken, and keep shipping.

On GitHub I work in public with Cursor, Claude Code, Next.js, and Supabase. On Upwork I help founders who already have a product, often one built fast with AI tools, and now need someone to stabilize auth, billing, and deploys.

I have been doing this for 7+ years and have shipped 120+ projects for US and EU teams. The work I care about is the layer after the demo: RLS, webhooks, Vercel, and the next version.

If you want help with a build, a messy repo, or a site that should rank and convert, email me at zlatkomarjanovic.zm@gmail.com.

LinkedInX / TwitterGitHubWebsiteUpwork
Older articleAI Receptionist for MedSpas: Calculate the Missed-Call Leak Before You Buy OneNewer articleYour Longevity Clinic Website Looks Expensive. That Is Why Nobody Books.

Frequently asked questions

Is the Supabase service_role key visible in Lovable apps?

Yes, if the client was created with the service_role JWT or if that value was stored under a VITE_ name.

Does Row Level Security protect me if service_role is in the frontend?

No. The service_role role has BYPASSRLS. Policies never run for that key.

What should I do first if I find the key in DevTools?

Treat it as compromised. Rotate, replace every consumer, then delete or deactivate the leaked key.

Are the new sb_secret_ keys safe in a browser because they return 401?

No. A non-browser script can still use the key. Delete a leaked secret key.

Is this a reason to rewrite the Lovable app in Next.js?

Usually no. The fix is key placement and Edge Functions, not a new frontend framework.

When should I hire a developer for a leaked Supabase key?

Hire as soon as real users or payments exist and you cannot prove the key is gone. Buy a hardening pass, not a redesign.

Related