Stripe Keys in the Browser: The Mistake We See Every Week
Publishable keys belong in the frontend. Secret keys never do. Here is how they end up in bundles anyway.
Stripe uses two kinds of keys, and the difference matters more than any other config decision you will make in your first month of running a paid product.
The two keys
- pk_live_… or pk_test_… is the publishable key. Safe in the browser. Designed to be shipped to the client. Only allows actions a customer should be able to take, like creating a payment method on their own card.
- sk_live_… or sk_test_… is the secret key. Server-only. Can charge any saved card, refund payments, read your full customer list, and create new API keys. Treat it like a database password.
How sk_live_ ends up in JavaScript anyway
It almost never happens on purpose. It happens through one of three boring routes.
- Copy-pasting an env example into a client component because the AI tool generated both halves at once and you did not notice which side was server-only.
- Committing the full .env to a public repo. Search GitHub for sk_live_ and you will find fresh leaks every hour.
- Logging the entire config object during a debug session and shipping the build with the log still in place.
// Bad: this runs in the browser bundle
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
// Good: server route only
export async function POST(req: Request) {
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
// …charge logic
}What to do the moment you suspect a leak
- Rotate the key in the Stripe dashboard. This invalidates the leaked one immediately. Do not delay this step to investigate first.
- Search your git history with git log -p -S 'sk_live_' to confirm the scope. Rewriting history does not help if it was ever public.
- Check Stripe → Developers → Events for any unfamiliar activity in the last 24 hours.
- Update the key in your deployment environment, redeploy, and verify charges still work in test mode.
Stripe is generous about rotation and will not penalize you for catching this early. The cost of a leaked sk_live_ on a busy weekend, however, is real and almost always avoidable. Run a report on your homepage and bundle before you launch, not after.