Leaked Stripe or Supabase keys in a Lovable or Bolt client bundle: how to find and fix them
Run a free check: FlowWatch signs up, logs in and runs a Stripe test checkout on your app, then scans for exposed keys. You get a shareable report. Run the free check at flowwatch.org
You shipped with Lovable, Bolt, Cursor or a similar AI tool. The app works. Then someone opens DevTools, searches the JavaScript, and finds a Stripe secret key or a Supabase service_role key. That is not a theoretical risk. AI-generated front ends often put server secrets into code that the browser downloads.
Which keys must never be in the browser
- Stripe
sk_liveorsk_test. Secret keys unlock charges, refunds and customer data. Only publishable keys (pk_) belong in client code. - Stripe webhook signing secrets (
whsec_). These verify that an event really came from Stripe. They belong only on the server. - Supabase
service_rolekey. It bypasses Row Level Security. The browser may use the anon / publishable key; it must never useservice_role.
The anon key alone is fine if every table has RLS policies that check auth.uid() (or equivalent). The problem is when the wrong key ships, or when RLS is off.
A 5-minute scan of your live app
- Open your production URL in a private window.
- Open DevTools → Sources (or Network → the main JS bundles).
- Search the loaded JavaScript for:
sk_live,sk_test,whsec_,service_role, and longeyJJWTs that look like Supabase secret keys. - If you find any of those, treat them as compromised: rotate them in the Stripe or Supabase dashboard first, then remove them from client code and redeploy. Do not only delete the string from the repo; anyone who already downloaded the old bundle still has the old key until it is revoked.
- While you are there, open the Network tab logged out and hit an API that should return your data. If rows come back without a session, RLS is not protecting you.
Why AI builds leak these
- A prompt asks for "Stripe checkout" and the model puts the secret key next to the publishable one in a
.envfile that gets bundled. - A serverless function and the front end share one env file, and the build tool inlines everything into the client.
- Supabase examples show
service_rolefor admin scripts; that snippet gets pasted into a React component.
Fix pattern that sticks
- Keep secrets only in server-side env vars (host dashboard, Edge Function secrets, or a backend you control).
- Call Stripe and privileged Supabase operations from that server path only.
- After every deploy that touches auth, payments or env vars, re-run the DevTools search above.
- Prefer a scheduled check so a later prompt cannot quietly put a secret back into the client.
Automating the leak scan
FlowWatch's free check includes a light scan for exposed keys, plus a real signup, login and Stripe test-mode checkout. It refuses to run if it finds live keys. Start here: flowwatch.org.
Contact: hello@flowwatch.org