claude-code - 💡(How to fix) Fix Claude Code + Vite: secret keys end up in the client bundle during POCs — suggest a built-in guardrail [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#52008Fetched 2026-04-23 07:39:01
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
labeled ×3

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.

Root Cause

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.

RAW_BUFFERClick to expand / collapse

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

extent analysis

TL;DR

To prevent API key exposure, use a backend proxy route instead of client-bundled environment variables for sensitive keys.

Guidance

  • Identify and review all API keys and secrets currently stored in client-bundled environment variables (e.g., VITE_GEMINI_API_KEY) and consider migrating them to a secure backend solution.
  • Implement a proxy server (e.g., using Cloud Functions or Express) to handle API requests, keeping sensitive keys secure on the server-side.
  • For real-time use cases, explore ephemeral tokens (e.g., Gemini Live, OpenAI Realtime) as an alternative to long-lived API keys.
  • Verify that spending limits are properly set on cloud providers (e.g., Google Cloud) to prevent unexpected charges.

Example

// Example proxy route using Express
const express = require('express');
const app = express();

app.get('/proxy/gemini', (req, res) => {
  const geminiApiKey = 'YOUR_SECURE_API_KEY';
  // Use the API key to make a request to the Gemini API
  // and return the response to the client
});

Notes

This solution focuses on preventing API key exposure through client-bundled environment variables. However, it's essential to also review and address any underlying issues with spending limits and billing alerts on cloud providers.

Recommendation

Apply a workaround by implementing a backend proxy route for sensitive API keys, as this will provide an additional layer of security and help prevent similar issues in the future.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

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?"

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING