Resources/Guide

Leaked Gemini API key? Cap the damage per key, not per project.

Google's spend controls work at the project or billing-account level. If a Gemini key has to live anywhere near client code, give that key its own limits and a revoke switch, so one leak becomes a small, bounded problem instead of a weekend-sized bill.

6 min read·October 2026·KeyVault Edge Team

Why Vite and AI Studio apps leak Gemini keys

Any variable prefixed VITE_ is compiled into the JavaScript bundle your users download. The same goes for NEXT_PUBLIC_ and REACT_APP_. Putting the key in a .env file doesn't change that. Google API keys start with a recognisable prefix, so automated scanners that crawl deployed sites find them easily.

Developers have described what happened next on Google's own forum this year:

If your key just leaked: the first hour

  1. Delete or regenerate the key in Google Cloud Console → APIs & Services → Credentials.
  2. Check the other keys in the same project. An unrestricted key gains Gemini access the moment the API is enabled.
  3. Restrict every remaining key to only the APIs it needs.
  4. Set a budget alert and spend controls on the project, then open a Cloud Billing case with the exact abuse window.
  5. Rebuild the app so the real key is not in the bundle (options below).

Getting the key out of the bundle

Option 1: your own backend. A serverless or edge function holds the key as a secret and your frontend calls it. Free, and the right answer if you'll also build rate limiting, per-user budgets and alerting.

Option 2: KeyVault Edge. Store the Gemini key once and get a kvt_ token. Your server-side code (a serverless function or route handler, which your Vite frontend calls) sends requests to our edge proxy with two headers plus an Origin matching one of the token's allowed hosts. The proxy adds the real key and forwards the request to Google:

// Server-side only, e.g. api/generate.ts — never in the Vite bundle
const res = await fetch(
  "https://proxy.keyvaultedge.com/v1beta/models/gemini-3.5-flash:generateContent",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-KV-Token": process.env.KVE_TOKEN, // kvt_… token, not your Gemini key
      "X-KV-Target": "https://generativelanguage.googleapis.com",
      Origin: process.env.APP_ORIGIN, // one of the token's allowed hosts
    },
    body: JSON.stringify({ contents: [{ parts: [{ text: "Hello" }] }] }),
  }
);

What each token limits

Requests per minute, per token

Each token has its own rate limit, enforced at the edge. A scraped token can't fire thousands of calls a minute.

Endpoint allowlist

Limit a token to the exact calls your app makes, e.g. generateContent on one model. Requests to image or other expensive endpoints are refused.

Monthly cost cap (estimated)

Each token can carry a monthly spend cap. The proxy estimates cost from the usage Gemini reports, including streamed responses, and blocks the token once the cap is reached.

One-click revoke

Kill a token from the dashboard and the next request is refused. Your real Gemini key never needs rotating because it was never in the app.

Alerts on unexpected hosts

Each token is bound to your domains. Calls from other origins are rejected and logged, and alerts go to email, Slack or a webhook.

What this does not do

  • A token is still a credential: if it's copied, it can be replayed. The host check reads Origin, which browsers can't fake but a script on a server can. The protection is that every token has hard limits and can be revoked in one click.
  • The cost cap is an estimate from the usage Gemini reports, not Google's invoice.
  • We sit in the request path. If the proxy is down, proxied calls fail.

Move your Gemini key behind KeyVault Edge

14-day free trial, then plans from $9/month. Want help? Email support@keyvaultedge.com and we'll walk you through the setup.

Start free trial