Is my Bolt app secure?

Bolt is very good at getting you from an idea to a deployed app without stopping. The problem is that the thing it's best at โ€” never making you think about the boundary between your machine and the internet โ€” is exactly the thing security depends on.

Most of what goes wrong in a Bolt app traces back to one misunderstanding, and it's a misunderstanding Bolt's own preview quietly encourages.

1. The preview lies to you about what's private

While you're building, Bolt runs your whole project inside a WebContainer โ€” a Node environment running in your browser tab. It's a genuinely clever trick, and it means your "server" code and your frontend code are both executing in the same place, on your own machine, where nobody else can see either of them.

So during development, putting an API key in a file feels fine. It works, nothing warns you, and the key is genuinely private โ€” because it's on your computer.

Then you deploy. The parts that were "server" code during preview don't automatically become a server. If your app deploys as a static site, there is no backend at all โ€” every file that ends up in the build is downloadable, and any key inside it is public.

The question worth asking about any secret in a Bolt project is not "is this in a config file?" but "after the build, does this end up in something a browser downloads?" If yes, it's published.

2. VITE_ is a publishing instruction

Bolt projects are usually Vite-based, and Vite has a rule that catches almost everyone: only variables prefixed VITE_ are visible to your app code. So when a variable seems to be missing at runtime, the obvious fix is to add the prefix โ€” and it works immediately.

What actually happened is that Vite substituted the value directly into your JavaScript bundle at build time. The prefix isn't a visibility setting, it's a decision to ship the value to every visitor.

Grep your project for VITE_ and read every result. If the name contains SECRET, PRIVATE, SERVICE_ROLE, or the name of something you pay for, that value needs to move server-side and then be rotated.

3. Calling AI and payment APIs from the browser

A Bolt app often has no backend at all, so when you ask for a chatbot the straightforward thing is a fetch to OpenAI or Anthropic directly from a component. It works in the preview. It works in production too โ€” for you and for whoever finds the key.

If you see dangerouslyAllowBrowser: true, that's the SDK telling you it noticed. It's the one place the tooling actually warns you, and it's phrased as a flag you can switch off rather than a mistake.

The fix is a small serverless function that holds the key and forwards the request โ€” a Netlify or Vercel function, or a Supabase edge function if you're already using Supabase. Add a rate limit while you're there: an open AI proxy is free credits with your name on the invoice.

My app calls the OpenAI API directly from the browser. Create a serverless function that makes the call using a key from a server-side environment variable, change the frontend to call that function instead, remove dangerouslyAllowBrowser, and add basic rate limiting to the function.

4. Where your environment variables actually live after deploy

A .env file in your project is a local development convenience. Your host does not read it โ€” you set environment variables in the host's own dashboard, and if you skip that step the app breaks in production in a way that tempts people into hardcoding the value "just to get it working".

Two things to check:

5. If you added a database

Bolt apps commonly use Supabase. If yours does, your browser talks to the database directly using a public key, and the only protection is Row Level Security. Off, or set to allow everything, means anyone can read and write every row โ€” not just their own.

That deserves more space than a paragraph: the RLS section of the Lovable guide covers it properly, and applies identically here.

Before you ship

Bolt changes quickly, and the specifics of its deploy flow may have moved since this was written. The check that doesn't go stale: build your app, then search the build output for anything that looks like a key. Whatever is in there is public.

Check it in about ten seconds

vibecheck scans your project folder or your live URL for everything on this page and explains what it finds in plain English โ€” with a fix prompt you paste straight back into Bolt.

Scan my app โ€” free