Is Bolt.new safe?
Yes, with one documented default that publishes your most powerful database credential to every visitor. Here is what to check in your own build, in order.
- security
- vibe coding
- bolt
Yes, and there is one specific default worth knowing about before you launch: following Bolt’s own database documentation to the letter puts your Supabase service role key, the credential that bypasses every access control you have, into a JavaScript file that anyone can download.
That is not a rumor or an inference from generated code. It is written in two sets of documentation that are each correct on their own and dangerous when read together, and you can verify it in about two minutes.
The five characters that decide it
Bolt scaffolds Vite projects. Vite has exactly one rule about environment
variables, stated plainly in
its documentation: “Variables prefixed
with VITE_ will be exposed in client-side source code after Vite bundling.”
The same page carries the warning:
VITE_*variables should not contain sensitive information such as API keys. The values of these variables are bundled into your source code at build time.
Now read Bolt’s
introduction to databases,
written for people who are new to databases. It tells them that “environment
variables keep these values private,” and then lists the variables to put
Supabase credentials in, including VITE_SUPABASE_SERVICE_ROLE_KEY.
Both pages are right about what they say. Vite is right that the prefix publishes. Bolt is right that environment variables keep credentials out of source control, which is a real benefit. Neither page tells the reader that the prefix, not the file, is what decides who can read the value. A builder following the instructions ends up with the most powerful credential in their project compiled into a public bundle.
What makes it a launch blocker rather than an untidiness is what that key is.
Supabase’s documentation says
the service role key “uses the BYPASSRLS attribute, skipping any and all Row
Level Security policies you attach,” and instructs you never to “add it to web
pages, public documents, source code.” It is the master key. Every policy you
write is irrelevant to whoever holds it.
Check your own build in two minutes
Do not reason about this from your source. Read what actually shipped:
npm run build
grep -rEo "eyJ[A-Za-z0-9_-]{20,}|sb_secret_[A-Za-z0-9]{20,}|sk-[A-Za-z0-9]{20,}" dist/
eyJ starts a base64url-encoded JWT header, which is what legacy Supabase keys
are. sb_secret_ prefixes the newer Supabase secret keys, and sk- prefixes
OpenAI keys. Anything that matches is public.
Your anon key matching is expected. It is designed to ship in the frontend, and Supabase calls it safe to expose, but only because Row Level Security is what makes it safe. So run the second check too:
select tablename, rowsecurity
from pg_tables
where schemaname = 'public';
Bolt generates Supabase migrations that create tables without adding policies.
Any row reading rowsecurity = false is readable by anyone holding the anon key
from your bundle, which is everyone. This is the same mechanism behind
CVE-2025-48757, the
Lovable disclosure that confirmed 170-plus exposed production apps. The CVE was
filed against Lovable, and the failure belongs to the backend rather than the
builder, so it applies to a Bolt project on Supabase in exactly the same way.
The RLS explainer covers why.
What Bolt genuinely gets right
A comparison that only lists faults is marketing, so here is the other side.
Bolt’s deployment target is Netlify, which means the server you need in order to fix the first problem already exists and costs nothing. Some generators leave you with a static bundle and no obvious place to put a secret. Bolt does not: moving the call into a Netlify function is a ten-minute change, not an architecture decision.
Bolt is also unusually transparent about what it produces. You can see the file tree, read every generated file, and edit it directly. That matters for security review in a way that is easy to undervalue, because a tool that hides its output makes an audit impossible regardless of how good the output is.
And the underlying stack is a good one. Supabase gives you real Postgres row-level access control and a real auth system. The primitives are correct; the default wiring is what needs a second look.
What “safe” can actually mean here
There is no version of this question with a platform-level answer, because Bolt does not run your app. It writes it once and hands it to you, and everything after that is your deployment, your keys, and your tables.
The version with an answer is narrower and checkable: does your deployed bundle contain a credential that bypasses your database policies, and do those policies exist and deny. Two commands, both above, both answerable today.
If they pass, the interesting risk moves to the places a grep cannot reach: a key that leaked in an early commit and is still in your git history even though the working tree is clean, a webhook that never verifies its signature, an endpoint that authenticates the caller and never checks whether the record belongs to them. The full fix list walks the first set, and Bolt.new security covers what a scan reaches that a checklist cannot.
The default is the story
Four of the five things worth fixing in a Bolt app are ordinary discipline that any app needs. The first one is different, and it is the reason this question gets asked at all.
The difference between a private credential and a public one was five characters in a variable name, documented accurately in one place, omitted in another, on a page written for people who by definition would not know to look. Bolt is not unsafe. It has a default that looks identical whether or not you got it right, which is a harder problem than an unsafe default, because there is nothing to notice.