Bolt.new app exposing keys? Where secrets should live
Bolt.new usually generates a Vite frontend, and a Vite frontend can't keep a secret. This page shows how to check the bundle you actually deployed and where each kind of key belongs on the hosts Bolt apps typically use.
Short answer: If a secret key is in your Bolt app's frontend code or a VITE_ variable, it's in the deployed JavaScript. Revoke it, move the call into a server function (a Supabase Edge Function or a Netlify Function), store the new key in that function's environment, and redeploy.
This guide covers one problem: secret keys in a Bolt.new app. For a broader review of Bolt, v0 and Replit apps, see Bolt, v0 & Replit app security.
Why Bolt apps leak keys
Most Bolt projects are a Vite + React frontend, often with Supabase as the backend, deployed to Netlify or Bolt's own hosting. When you ask for "connect to OpenAI" or "add Stripe payments", the shortest path is to call the API straight from a component and read the key from import.meta.env.VITE_.... Vite inlines those values at build time, so the key ships in the static files. The VITE_ guide shows this step by step.
Check the deployed bundle [manual]
- Open your deployed URL (for example
yourapp.netlify.appor your custom domain). - DevTools, Network, filter JS, reload, then search all sources with Ctrl+Shift+F (Cmd+Option+F on a Mac).
- Search for
sk_live_,sk-proj-,sk-ant-,AKIA,AIza,sb_secret_andeyJ. Decode anyeyJJWT and check itsrole:anonis expected,service_roleis an emergency. - In Bolt, search the project files for
VITE_and list every variable. Anything secret on that list is leaking. - Open
yourapp.netlify.app/.envin a browser. You should get a 404 or your app's HTML, never a list ofKEY=valuelines.
Where each secret should live
- Supabase is your backend: use a Supabase Edge Function. Set the secret with
supabase secrets set NAME=valueor in the dashboard under Edge Functions, Secrets, and read it withDeno.env.get("NAME"). - Deploying to Netlify without Supabase: use a Netlify Function in
netlify/functions/. Add the variable in the Netlify UI under Site configuration, Environment variables, with noVITE_prefix, and readprocess.env.NAMEinside the function only. - Public values (Supabase URL and anon key, Stripe
pk_live_) can stay inVITE_variables.
Fix it, in this order
- Revoke or roll the leaked key [manual] at the provider. The deployed copy is public until you do.
- Ask Bolt to restructure.
Security fix: secret API keys are exposed in client-side code. For every VITE_ variable or hard-coded value that is a secret (Stripe sk_ or rk_ keys, OpenAI, Anthropic, AWS, Supabase service_role or sb_secret_ keys), move the code that uses it into a server-side function (a Supabase Edge Function if this project uses Supabase, otherwise a Netlify Function). Read the key from the function's environment without a VITE_ prefix, require an authenticated user, and have the frontend call the function. Remove the secret from all frontend files and from .env VITE_ entries.
- Add the new key to the function's environment [manual], as described above. Don't paste it into the Bolt chat inside code.
- Redeploy, then repeat the bundle check. If you deploy to more than one place, check each URL.
Make it stick
- If the project is synced to GitHub, make sure
.envis in.gitignore, and turn on GitHub push protection. A key that was committed stays in history; revoking it is what protects you. - Re-check after every feature that adds an integration. Regenerated components often bring the client-side call back.
What the free scan checks here (and what it doesn't)
It fetches your deployed page and up to 25 linked scripts and flags Stripe sk_live_/rk_live_, OpenAI, Anthropic, AWS AKIA/ASIA, Google AIza, and Supabase service_role and sb_secret_ keys. A Supabase anon key is reported as info only; the scan doesn't test your tables. It also checks /.env, /.git/HEAD, HTTPS and the HTTP-to-HTTPS redirect, and four security headers: CSP, HSTS, X-Frame-Options or frame-ancestors, and X-Content-Type-Options.
It doesn't read your Bolt project files, your server functions, or your Netlify settings. Those are [manual].
FAQ
- Are secrets in Bolt's .env file safe?
- Only the ones without a VITE_ prefix, and only if no client code reads them. Anything the browser code uses is copied into the bundle. Also make sure .env isn't deployed to your public folder or pushed to a public GitHub repo.
- My Bolt app works in the preview. Why does the deployed version leak?
- The preview runs the same frontend code, so it leaked there too; deploying just made it public. Whatever the frontend reads at build time is in the files your host serves.
- What does the free scan check on a Bolt app?
- It reads your deployed page and up to 25 linked scripts and flags Stripe, OpenAI, Anthropic, AWS, Google and Supabase secret keys. It also checks whether /.env or /.git/HEAD is publicly served, and HTTPS plus four security headers.