Bolt.new security: 7 things to verify before sharing the URL.
src/ instead of .env, missing or permissive Supabase RLS, sourcemaps deployed to production, source-routes accidentally exposed at /_routes, default-credentials components scaffolded without auth, CORS wide-open in generated functions, and Stripe wiring that lands the live key in client. This post is the seven-item audit, with the exact commands to test each one.
Bolt is fast. Faster than Lovable for full-stack scaffolds because the WebContainer runs the dev server, runs the migrations, and shows you the live preview without leaving the browser. The downside: it's also faster at making the kind of mistakes that ship straight to production. Here's the audit.
1. Env vars in src/, not in .env
Bolt's prompt-driven file editor often inlines API keys directly into source files when you say "wire up Stripe / Supabase / OpenAI." The keys end up in src/lib/supabase.ts or src/api.ts rather than in .env with a Vite/Next prefix.
Test:
find src -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' \) \
| xargs grep -lE '(sk_live_|sk-(proj-)?[A-Za-z0-9]{20}|eyJ[A-Za-z0-9_-]+\.eyJ)'
Fix: move keys to .env; in Vite use import.meta.env.VITE_* only for keys that are safe in the browser; keep server-only keys without the VITE_ prefix and reference them only in API routes / Edge Functions.
2. Supabase RLS — the standard issue
Bolt's templates wire @supabase/supabase-js with the anon key but don't generate RLS policies. Your client can read every table with the anon key.
Test from outside:
curl 'https://<ref>.supabase.co/rest/v1/users?select=*&limit=5' \
-H 'apikey: <your-anon-key>' \
-H 'Authorization: Bearer <your-anon-key>'
If you get rows back, the table is open. Run a vibecheck scan for the autofix RLS SQL, or read the response guide.
3. Sourcemaps deployed to production
Vite's default is to emit *.map files in dist/. Bolt deploys what's in dist/, sourcemaps and all. That gives any visitor the full unminified source — including comments, credentials that survive minification, internal logic.
Test:
curl -I https://your-app.netlify.app/assets/index-AbCdEf12.js.map
If the map returns 200 with a JSON body, your unminified source is public. Vite config:
// vite.config.ts
export default defineConfig({
build: { sourcemap: false } // production: false; only enable for debugging
});
4. Generated API functions with permissive CORS
When Bolt generates a Netlify or Vercel serverless function, the default template often includes:
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
}
That combination is forbidden by browsers but accepted by some non-browser clients and proxies. It also indicates the dev didn't think about origin restrictions.
Test:
curl -I https://your-app/api/<function> -H 'Origin: https://attacker.example.com'
# Look for: Access-Control-Allow-Origin: * combined with Allow-Credentials: true
Fix: set ACAO to your actual frontend origin (or use an allowlist), not *. If you don't need cookies/auth across origins, drop Allow-Credentials entirely.
5. Stripe wiring with sk_live_ in client
If you said "add Stripe checkout" while building, Bolt likely accepted whatever Stripe key you provided and wired it client-side. If you pasted sk_live_ instead of pk_live_, that secret key is now in your bundle.
Test:
curl -sL https://your-app/ | grep -oE 'sk_live_[A-Za-z0-9]{24,}'
If anything matches: rotate immediately at dashboard.stripe.com/apikeys. The publishable key (pk_live_) is the one that belongs in the browser; the secret key (sk_live_) only ever lives in your server-side function.
6. WebContainer state leaked in deploy artifacts
Bolt's WebContainer persists state — including node_modules, .cache, sometimes .env — into the deploy directory if not explicitly excluded. Look for these in your deployed output:
curl -I https://your-app/.env
curl -I https://your-app/node_modules/some-pkg/package.json
curl -I https://your-app/.bolt/state.json
curl -I https://your-app/_routes # Vite's route manifest
Any 200 here is bad. Update your deploy ignore list (.gitignore, netlify.toml publish dir, vercel.json's output config) so only dist/ ships.
7. Routes meant for development still exposed
AI scaffolds frequently include /admin, /debug, /test, or /dev routes that were created for testing and never removed. Bolt's preview keeps these alive in production unless you tell it to.
Test:
for path in admin debug dev test internal staging _admin api/admin; do
echo -n "$path: "; curl -sIo /dev/null -w '%{http_code}\n' "https://your-app/$path"
done
Anything returning 200 should either be deleted or gated behind authentication. The vibecheck scanner probes most of these automatically.
One command does items 2–7
Items 1 (env vars in src/) requires looking at your source code; we can't see that from outside. Items 2 through 7 are exactly what the vibecheck scanner tests against any deployed URL.