Did I Leak My Stripe Key? pk_live vs sk_live Explained

Found your Stripe key in your frontend? Whether it's an emergency depends on one letter. Learn pk_live vs sk_live and exactly what to do if you leaked the secret one.

Barret8 min read

You found a Stripe key in your frontend code — maybe a scanner flagged it, maybe you spotted it yourself in the browser — and your stomach dropped. Stripe handles your money. If your Stripe key is out in the open, can someone drain your account?

Here's the answer that will save you a lot of stress: whether you have a problem depends on one letter. A leaked Stripe key is sometimes completely fine and sometimes a real emergency, and the difference between the two is the prefix pk versus sk. Most founders who panic about this leaked the harmless one.

This post explains the two Stripe keys in plain terms, shows you how to tell which one you exposed, and walks through the exact steps to take if it turns out to be the dangerous one. We won't be dismissive — if you leaked the secret key, it matters — but we also won't let you lose a night's sleep over a key that's supposed to be public.

⚡ TL;DR

  • Stripe has two live keys. pk_live_… is the publishable key — it's meant to ship in your browser. Finding it in your frontend is normal, not a leak.
  • sk_live_… is the secret key — full access to your Stripe account. If this one is in your frontend, treat it as an emergency and rotate it now.
  • Tell them apart by the prefix: pk_ = publishable (fine), sk_ = secret (rotate).
  • If the secret key leaked, the fix is fast: roll the key in the Stripe dashboard, move the new one server-side, and check your logs.

The two Stripe keys, in plain English

Stripe gives every account a pair of API keys, and they do very different jobs.

The publishable key (pk_live_…) is the public one. Its entire purpose is to live in your frontend, where your checkout form runs. When a customer enters their card, the publishable key tells Stripe which account this payment belongs to and lets Stripe's secure form tokenize the card. That's it. The publishable key cannot create charges on its own, issue refunds, read your customer list, or move money out of your account. Stripe designed it to be visible — it assumes anyone can read it, and the system is safe anyway.

The secret key (sk_live_…) is the powerful one. It has full access to your Stripe account. With the secret key, you (or anyone holding it) can create charges, issue refunds, pull your entire list of customers and their payment history, and manage your account. It is meant to live only on a server you control, where your users can never see it. The browser should never receive it.

The naming is doing you a favor here. "Publishable" literally means safe to publish. "Secret" means keep it secret. Stripe named them this way on purpose.

There's also a test pair — pk_test_… and sk_test_… — that only touches Stripe's sandbox. A leaked test secret key can't affect real money, though you should still rotate it for hygiene. The keys that matter for real risk are the live ones.

How to tell which key you leaked

This is the part that resolves most of the worry. Look at the prefix of the key you found:

  • Starts with pk_live_publishable key. Public by design. This is supposed to be in your frontend. Not a leak. You can stop worrying about this one.
  • Starts with sk_live_secret key. This should never be in your frontend. If it's in your browser-delivered code, this is a real exposure and you should act now (steps below).
  • Starts with pk_test_ or sk_test_test keys. Sandbox only, no real money at stake. Rotate the secret test key for tidiness, but don't panic.

That's the whole diagnosis. One prefix. If you only have time to remember one thing from this article: pk is publishable and fine; sk is secret and serious.

🐺 Not a real problem

A Stripe pk_live key in your frontend is not a leak. It's the publishable key, and it's meant to ship in the browser. If a scanner flagged your pk_live as an exposed secret and told you to rotate it, that tool is crying wolf — and it's worth asking what else it's wrong about.

Where each key is supposed to live

Knowing where the keys belong tells you whether you have a problem at a glance.

The publishable key belongs in your frontend. It's correct for it to appear in your JavaScript bundle, in a pk_live_… string your browser loads, or behind a public build variable like VITE_STRIPE_PUBLISHABLE_KEY or NEXT_PUBLIC_STRIPE_KEY. That's by design.

The secret key belongs only on the server. Correct homes include:

  • A backend API route on a server you control.
  • A serverless or edge function (for example, a Supabase edge function or a Vercel serverless function).
  • A server-side environment variable that is never prefixed with VITE_, NEXT_PUBLIC_, or REACT_APP_, because those prefixes deliberately ship the value to the browser.

The pattern is: your frontend talks to your server, and your server talks to Stripe with the secret key. The customer's browser never sees sk_live. When an AI builder wires up payments the quick way, it sometimes skips that middle step and calls Stripe straight from the browser with the secret key — which works in a demo and leaks the key to every visitor. That's the mistake to look for.

How a Stripe secret key ends up in your frontend

If you did leak the secret key, it probably happened one of these ways, and none of them mean you did anything dumb — they're common in AI-built apps:

  • The AI hardcoded it. You asked your builder to "set up Stripe payments," and the fastest route to a working demo was to drop the secret key into the code that runs the feature. If that code runs client-side, the key ships to every visitor.
  • It's behind a public build prefix. A secret key stored as VITE_STRIPE_SECRET_KEY or NEXT_PUBLIC_STRIPE_SECRET gets baked into the frontend bundle by the build tool, exactly as those prefixes instruct.
  • It's in a published source map. If you shipped source maps to production, your original code — secret key included — can be downloaded and read even if it isn't visible in the minified bundle.

These are the same routes any secret takes into a frontend; we cover them in depth in the pillar guide, exposed secrets and API keys in frontend code.

How to check your own app

A quick way to see which Stripe key, if any, is reaching your users:

  1. Open your live app and open browser developer tools (right-click → Inspect, or F12).
  2. Search the loaded JavaScript (Ctrl/Cmd-Shift-F in dev tools) for sk_live_. If you find it, your secret key is exposed — go to the fix below. Searching for pk_live_ will likely turn up your publishable key, and that's fine.
  3. Check your code and environment variables for any secret key behind a VITE_, NEXT_PUBLIC_, or REACT_APP_ prefix. Those values ship to the browser.
  4. Look for published source maps (readable, un-minified code or .map files in the Sources tab). A secret key can hide there even when it's absent from the bundle.

Not sure whether you leaked the safe key or the serious one?

Run a free, read-only scan of your live app — no install, results in under a minute. Is My Site Hackable? flags a real exposed secret and tells you when it's just the public key.

Scan my app free →

What to do if your secret key (sk_live) leaked

If you confirmed an sk_live key in your frontend, here's the order of operations. It's fixable, and these steps take minutes, not days.

  1. Roll the secret key in the Stripe dashboard. Go to Developers → API keys, find your secret key, and roll (regenerate) it. Stripe lets you roll a key and optionally expire the old one immediately. Once you do, the leaked key stops working — which is what makes this the most important step. Do it first.
  2. Put the new key server-side only. Don't paste the new secret key back into frontend code, or you'll recreate the exact hole. Move it into a backend route, a serverless function, or an edge function, stored in a server-only environment variable. Your frontend should call your server, and your server calls Stripe.
  3. Review your Stripe activity. While the old key was exposed, could anyone have used it? Check Payments, Refunds, and the Events / logs in your dashboard for charges or refunds you don't recognize. Stripe's logs show API activity tied to the key.
  4. Confirm the leak is gone. Re-check your live bundle for sk_live_ to make sure the new key isn't shipping the same way.

For the full, provider-agnostic version of this — rotate, then audit, then monitor, in that order — see a key just leaked: rotate, audit, monitor.

FAQ

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

Yes. The publishable key is designed to live in your frontend where anyone can read it. It can't charge cards on its own, issue refunds, or read your customer data. Seeing pk_live in your browser code is the intended behavior, not a leak — no need to rotate it.

What can someone do with a leaked Stripe secret key?

A lot — which is why it's an emergency. The secret key (sk_live) has full access to your account: creating charges, issuing refunds, and reading your customers and their payment history. If it's exposed in your frontend, roll it in the Stripe dashboard immediately and move the new key server-side.

How do I know if I leaked pk or sk?

Read the prefix of the key you found. pk_live_ is the publishable key (public by design, fine). sk_live_ is the secret key (must stay server-side; rotate if exposed). The _test_ variants are sandbox-only and carry no real-money risk.

Will rotating my Stripe secret key break my app?

It can briefly, if your server is still using the old key. The fix is to update your server-side environment variable to the new key and redeploy. Once your backend uses the new key and the old one is expired, payments work normally — now without the exposed key.

The bottom line

A leaked Stripe key is one of the most common scares in AI-built apps, and most of the time it's a false alarm: the pk_live publishable key is meant to ship in the browser. The key that matters is sk_live — the secret key with full account access — and if that one is in your frontend, the fix is fast: roll it, move it server-side, and check your logs. An attacker can scan your bundle for an exposed sk_live in minutes. The point is to find it first, and to keep checking, because your AI ships new code on every deploy.

Find your gaps before an attacker does.

Is My Site Hackable? scans your deployed app for the exact issues in this article — exposed keys, missing RLS, open buckets — and tells you what's real and what's a false alarm.

Run a free scan →