Is Your Stripe Secret Key in Your JavaScript Bundle? Here's How to Check
If you used Cursor, Claude, or ChatGPT to add Stripe payments to your app, there's a good chance your sk_live_ key is sitting in your compiled JavaScript right now. Here's how to check in 30 seconds.
The Problem: AI Puts Your Secret Key in Client Code
Here's what typically happens:
You prompt your AI coding tool:
"Add Stripe checkout to my Next.js app"
The AI generates something like this in a React component:
// ❌ WRONG — this is a CLIENT component
"use client";
import Stripe from "stripe";
const stripe = new Stripe("sk_live_abc123...");
export function CheckoutButton() {
const handleClick = async () => {
const session = await stripe.checkout.sessions.create({
// ...
});
};
return <button onClick={handleClick}>Pay</button>;
}That sk_live_ key is now public
When Next.js compiles this component, the Stripe secret key gets baked into the JavaScript bundle. Every visitor downloads it. Anyone can open DevTools → Sources and search for "sk_live_" to find it.
What Someone Can Do With Your Stripe Secret Key
- Create charges against any customer in your account
- Read all customer data — emails, addresses, payment methods
- Issue refunds on any transaction
- Create and manage subscriptions
- Access your entire transaction history
This is not a theoretical risk. We've found live sk_live_ keys in 11 out of 100 AI-built apps we scanned.
How to Check in 30 Seconds
Method 1: Free Security Scanner (Easiest)
- Go to aiexposuretool.com/security
- Enter your site URL
- The scanner downloads your JS bundles and scans for
sk_live_andsk_test_patterns - Get results in 30 seconds — no signup needed
Free Security Scanner
Scans for 17 API key types including Stripe, OpenAI, AWS, and Supabase. Passive, read-only.
Method 2: Manual Check (DevTools)
- Open your site in Chrome
- Open DevTools (F12 or Cmd+Option+I)
- Go to Sources tab
- Press Cmd+Shift+F (search across all files)
- Search for
sk_live_orsk_test_ - If you see a match — your key is exposed
The Fix: Move Stripe to Server-Side
// ✅ CORRECT — Server-side API route
// /app/api/checkout/route.ts
import Stripe from "stripe";
import { NextResponse } from "next/server";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: [{ price: "price_xxx", quantity: 1 }],
success_url: "https://yoursite.com/success",
cancel_url: "https://yoursite.com/cancel",
});
return NextResponse.json({ url: session.url });
}// ✅ Client component — calls the API route
"use client";
export function CheckoutButton() {
const handleClick = async () => {
const res = await fetch("/api/checkout", { method: "POST" });
const { url } = await res.json();
window.location.href = url;
};
return <button onClick={handleClick}>Pay</button>;
}The secret key stays in .env.local (server only). The client component only calls the API route — no key exposed.
Publishable Key vs Secret Key — Quick Reference
| Publishable (pk_) | Secret (sk_) | |
|---|---|---|
| OK in client JS? | ✅ Yes | ❌ NEVER |
| Can create charges? | No | Yes |
| Can read customer data? | No | Yes |
| Can issue refunds? | No | Yes |
| Starts with | pk_live_ or pk_test_ | sk_live_ or sk_test_ |
| Where to use | Browser, React, Stripe.js | Server only (API routes) |
FAQ
What's the difference between Stripe publishable and secret keys?
Publishable keys (pk_live_ or pk_test_) are meant for client-side code — they can only create tokens, not charges. Secret keys (sk_live_ or sk_test_) have full API access: create charges, refund payments, read customer data, manage subscriptions. Secret keys must NEVER be in client-side JavaScript.
How do I check if my Stripe key is exposed?
Use AI Exposure Tool's free security scanner at aiexposuretool.com/security. It downloads your JavaScript bundles and scans for sk_live_ and sk_test_ patterns. Takes 30 seconds, completely passive.
My Stripe key is exposed — what do I do?
1) Go to Stripe Dashboard → API Keys → Roll key immediately. 2) Move the key to .env.local. 3) Create a server-side API route (/api/checkout) that uses the key. 4) Never import Stripe with a secret key in a client component. 5) Re-scan to verify the fix.
Can someone actually find my key from a JavaScript bundle?
Yes. Open any website → DevTools → Sources tab → search for 'sk_live_' or 'sk_test_'. If the key is in a client component, it's in the compiled bundle. Minification doesn't hide it — the full key string is still there.