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_live or sk_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_role key. It bypasses Row Level Security. The browser may use the anon / publishable key; it must never use service_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

  1. Open your production URL in a private window.
  2. Open DevTools → Sources (or Network → the main JS bundles).
  3. Search the loaded JavaScript for: sk_live, sk_test, whsec_, service_role, and long eyJ JWTs that look like Supabase secret keys.
  4. 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.
  5. 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 .env file 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_role for admin scripts; that snippet gets pasted into a React component.

Fix pattern that sticks

  1. Keep secrets only in server-side env vars (host dashboard, Edge Function secrets, or a backend you control).
  2. Call Stripe and privileged Supabase operations from that server path only.
  3. After every deploy that touches auth, payments or env vars, re-run the DevTools search above.
  4. 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