Bolt.new: How to Fix Exposed API Keys in Your Frontend
Updated 2026-10-17
Bolt.new commonly scaffolds Vite + React frontends. In Vite, any variable prefixed with VITE_ is inlined into the JavaScript that ships to browsers. When a prompt like "add OpenAI" leads to VITE_OPENAI_API_KEY, the secret becomes public the moment you deploy.
Find what shipped
Build your app and search the output for key prefixes. Anything you find in dist/ is readable by every visitor.
npm run build
grep -rEo "sk_live_[0-9A-Za-z]+|sk-proj-[A-Za-z0-9_-]+|sk-ant-[A-Za-z0-9_-]+|re_[A-Za-z0-9_]+" dist/ | sort -uMove the call behind a server route
Create a small serverless function (Netlify/Vercel function, Supabase Edge Function, or an Express route) that holds the key in a server-only environment variable and calls the provider. The browser calls your function instead.
Add authentication and a rate limit to that function — otherwise you have only moved the open door, not closed it.
// supabase/functions/chat/index.ts (Deno)
Deno.serve(async (req) => {
const { prompt } = await req.json();
const r = await fetch("https://api.openai.com/v1/responses", {
method: "POST",
headers: { Authorization: `Bearer ${Deno.env.get("OPENAI_API_KEY")}`, "Content-Type": "application/json" },
body: JSON.stringify({ model: Deno.env.get("OPENAI_MODEL"), input: String(prompt).slice(0, 4000) }),
});
return new Response(await r.text(), { status: r.status, headers: { "Content-Type": "application/json" } });
});Rotate, then redeploy
Removing the key from code does not un-leak it: old bundles may be cached by CDNs, browsers and archive crawlers. Revoke the exposed key in the provider dashboard, issue a new one, and store it only in server environment settings.
Checklist
- No
VITE_variable holds a secret - Provider calls happen in a server function
- Server function requires auth and is rate limited
- Exposed keys revoked and replaced
- Spending limits / usage alerts set at the provider
Copy-paste fix prompt
Find every `import.meta.env.VITE_*` usage that holds a secret (OpenAI, Anthropic, Stripe secret, Resend). Replace each with a call to a new server function that reads the secret from a server-only env var, requires the user's session, and applies a per-user rate limit. Remove the VITE_ variables and list the keys I need to rotate.FAQ
Does hiding the key in an environment variable fix it?
Only if the variable is server-only. In Vite, VITE_-prefixed variables are bundled into client code, so they are public.
Is my Stripe publishable key a problem?
No. pk_live_ and pk_test_ keys are designed for browsers. Only sk_live_ / rk_live_ keys are secret.
Check your deployed app in ~25 seconds
Free passive scan: leaked keys, Supabase exposure, public config files and headers.
Run a free scan