Security · Next.js (App Router)
I found an API key in my page source in Next.js (App Router)
The fix for Next.js (App Router)
13x detects your framework from the response and hands you this version rather than the generic one — below 50% confidence it hedges and gives you the generic one instead.
Rotate the key first — it is already public. Revoke and reissue it in the provider's dashboard before changing any code.
In the App Router, NEXT_PUBLIC_ is the whole story: that prefix inlines the
value into the client bundle at build time. Anything without it stays on the
server.
# .env.local
STRIPE_SECRET_KEY=sk_live_REPLACE_WITH_YOUR_KEY # server only
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_REPLACE_ME # public by designRead the secret from a server action or route handler, never from a component
that carries "use client":
// app/api/checkout/route.ts — runs on the server
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(request: Request) {
const session = await stripe.checkout.sessions.create({ /* … */ });
return Response.json({ url: session.url });
}Add import "server-only"; at the top of any module that reads a secret. It
turns "this accidentally got imported into a client component" from a silent
production leak into a build error.
Then verify the bundle is clean:
npm run build && grep -rE "sk_(live|test)_|AKIA[0-9A-Z]{16}" .next/static/On a different stack? The general version of this fix explains what 13x checks and why it matters, without assuming a framework.
Check your Next.js (App Router) site
113 deterministic checks against your live URL, in about 30 seconds. Framework detected from the response, so every fix comes back in the form your stack actually uses.
No signup. Results in 30 seconds.