← All guides
General

Exposed API Keys in Vibe-Coded Apps

·8 min read

To make a demo work in one shot, AI coding tools often call an API — OpenAI, Stripe, a database — directly from the browser, with the key right there in the frontend code. It works instantly, which is the trap: anything in client code is shipped to every visitor and readable in seconds. Independent reviews in early 2026 found exposed credentials across hundreds of vibe-coded apps.

Why a frontend key is a problem

A secret key is like a password for your account on that service. Once it's in the JS bundle, anyone can copy it and run up your bill, read your data, or send email as you. The fix is never to hide it better in the frontend — it's to move it to the server.

1. Find exposed keys

  • Open your deployed site, then View Source and open the main JS bundle.
  • Search (Ctrl/Cmd-F) for sk_, secret, service_role, api_key, and Bearer.
  • Check anything prefixed NEXT_PUBLIC_ (Next.js) or VITE_ (Vite) — those are deliberately shipped to the browser.

2. Move the call to the server

Put the secret in a server environment variable and call the third-party API from a server route, then have your frontend call *your* route. The key never reaches the browser.

// app/api/summarize/route.ts (server-only)
export async function POST(req: Request) {
  const { text } = await req.json();
  const r = await fetch('https://api.openai.com/v1/...', {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
    body: JSON.stringify({ /* ... */ }),
  });
  return Response.json(await r.json());
}

3. Rotate the exposed key

Moving the key doesn't un-leak the old one — anyone who already grabbed it can still use it. Go to the provider's dashboard, generate a new key, update your server env, and revoke the old one. Treat any key that has touched a chat, a screenshot, or a public commit as compromised.

Quick checklist

  • No secret keys (sk_, service_role, private API keys) in the client bundle.
  • Secrets live in server env vars, never NEXT_PUBLIC_ / VITE_.
  • Third-party calls go through your own server route.
  • Every exposed key rotated and the old one revoked.

FAQ

How do I know if a key is 'publishable' or 'secret'?

Providers usually prefix them: pk_ / publishable / anon are safe for the browser; sk_ / secret / service_role / private must stay server-side. When unsure, check the provider's docs.

I committed a key to GitHub and removed it — am I safe?

No. It stays in git history and may already be indexed by scanners. Rotate the key; deleting the commit is not enough.

LaunchPal provides launch readiness checks, not a professional penetration test.