Claude Code + Vite: secret keys end up in the client bundle during POCs — suggest a built-in guardrail

Resolved 💬 1 comment Opened Apr 22, 2026 by jmons54 Closed May 28, 2026

Context

I'm a solo founder. I was building a POC (dating app: Firebase + React + Flutter) with Claude Code. Speed over rigor — I wasn't reviewing security choices carefully, which is kind of the point of a POC.

What happened

Claude Code helped me wire up a Gemini API key into a Vite app via VITE_GEMINI_API_KEY in .env, consumed as import.meta.env.VITE_GEMINI_API_KEY. That's the standard Vite pattern and it "just works".

The problem: VITE_* env vars are inlined into the client bundle, which is publicly accessible. Within days bots scraped the bundle, extracted the key, and ran up ~€800 of Google Cloud charges before I noticed and rotated it.

This is partly on me — I also misconfigured GCP: I thought I'd set a spending limit, but it was actually just a billing alert. Two layers of "I assumed this was safe" stacked on top of each other.

A similar VITE_OPENAI_API_KEY leak happened on the same project (caught later, no exploitation that I'm aware of).

Why I'm filing this

I'm not pointing fingers — the assistant did what I asked and the pattern I used is everywhere on the internet. But this is exactly the kind of mistake where an assistant could save a non-senior dev a lot of money, especially in POC/solo-founder mode where nobody is reviewing.

Expected behavior

Claude Code should actively push back when the user tries to place a secret-shaped API key behind any client-bundled env var:

  • Vite: \VITE_*\
  • CRA: \REACT_APP_*\
  • Next.js: \NEXT_PUBLIC_*\
  • Flutter compile-time \--dart-define\ holding a secret

…and proactively propose the safe alternatives:

  1. Proxy the call through a backend route (Cloud Functions / Express / API route)
  2. Ephemeral tokens for realtime use cases (Gemini Live, OpenAI Realtime, WebRTC)
  3. Only accept client-side env vars for public-by-design keys (Firebase Web API key, reCAPTCHA site key, Stripe \pk_*\, Maps key with HTTP referrer restriction)

Ideally paired with a nudge on billing: "by the way, have you set a real spending cap — not just an alert — on the provider?"

Suggestion

A built-in guardrail: when Claude is about to generate code that places a value matching common secret prefixes (\sk-\, \sk-ant-\, \sk-proj-\, \AIza...\ outside a Firebase Web SDK context, etc.) into a client-bundled namespace, it should refuse and propose the backend route instead — even when the user is going fast.

Environment

  • Claude Code CLI
  • Vite 8 + React 19 + Flutter 3.41
  • Solo developer / POC mode

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗