Launch sale: 20% off Fix Pack, Deep Audit and Monitor through Nov 30, 2026. The scan stays free. See sale prices →
Home / Fix guides / Stripe secret key exposed

Stripe secret key (sk_live) exposed in front-end code: how to fix it

Critical

Stripe secret keys (sk_live_…, sk_test_…), restricted keys (rk_…) and webhook secrets (whsec_…) must only ever live on a server. Only the publishable key (pk_…) belongs in the browser. Note: Clerk also uses the sk_live_/sk_test_ prefix for its secret keys; the fix is the same.

Why it matters

With your secret key, anyone can read customer and payment data, create refunds or payouts, and change your account. Vibe-coded checkouts sometimes call the Stripe API directly from the browser, which requires putting the secret key there.

Quick fix

  1. Roll the key now in the Stripe Dashboard (Developers → API keys → ⋯ → Roll key).
  2. Remove it from client code and VITE_/NEXT_PUBLIC_ variables; keep only pk_ keys in the browser.
  3. Create Checkout Sessions/PaymentIntents in a server function and verify webhooks server-side with whsec_.
  4. Review Stripe Dashboard → Developers → Logs for API calls you did not make.

Step by step

1. Roll the key

Stripe Dashboard → Developers → API keys → find the key → Roll key. Choose to expire the old key immediately if it was live.

2. Move Stripe calls to the server

Move the call that needs the key to server-side code (a Supabase Edge Function, a Vercel/Netlify function, or a Next.js API route / server action) and store the key as a server-only environment variable. In Vite apps, any variable starting with VITE_ is bundled into the browser; in Next.js, anything starting with NEXT_PUBLIC_ is.

// api/create-checkout.js (Vercel function)
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export default async function handler(req, res) {
  const session = await stripe.checkout.sessions.create({
    mode: "payment",
    line_items: [{ price: "price_123", quantity: 1 }],
    success_url: "https://yourapp.com/success",
    cancel_url: "https://yourapp.com/cancel",
  });
  res.json({ url: session.url });
}

3. Check logs

Stripe Dashboard → Developers → Logs shows every API request with its source IP. Look for requests you don't recognize.

Prompt for your AI builder

Paste this into Lovable, Bolt, v0, Cursor or Replit, then review the changes before deploying.

A Stripe secret key is exposed in my front-end bundle. Remove all Stripe secret keys (sk_/rk_/whsec_) from client code and public env vars. Create a server-side endpoint that creates Stripe Checkout Sessions using process.env.STRIPE_SECRET_KEY, and have the front end call that endpoint and redirect to session.url. Add a webhook endpoint that verifies the stripe-signature header with STRIPE_WEBHOOK_SECRET. Only the publishable pk_ key may remain in client code.

FAQ

I deleted the key from my code. Am I safe now?

No. Once a key has shipped to browsers it should be treated as public. It is in old deployments, caches and anyone's saved copy of your JavaScript. Revoke it at the provider and create a new one; removing it from code only stops future leaks.

Is the Stripe publishable key (pk_live_) safe to expose?

Yes. Publishable keys are designed for browsers and can only do things like tokenize cards and confirm payments the server set up.

References

Check your app

Run a free scan

Want help fixing this?

We're opening a done-for-you fix service, a deep audit (database rules, auth, user-to-user data access) and continuous monitoring. Join the waitlist to get first access. No spam, and we never share your email.