Blog · ← All posts
Bolt.new Pre-Deploy Security Checklist
Last updated: October 2026 · 7 min read
Bolt.new generates full-stack apps in the browser, React, Next.js, or Vite, wired to Supabase, Netlify, or whatever backend your prompt described. The in-browser preview makes everything feel done. Deployment is one click. The security review in between is usually zero clicks, which is why this checklist exists.
Run these eight checks on your Bolt.new output before you ship. Each one maps to a real check class in Vibe-Code Audit, paste your code and we run them all in seconds.
1. Env vars the browser can read
Vite only exposes variables prefixed VITE_ to the browser, Bolt.new output sometimes forgets that, and sometimes does the opposite: marks a secret VITE_ for convenience so the frontend can reach it. Any key with that prefix ships in the JS bundle to every visitor.
// VULNERABLE — secret exposed to the browser const key = import.meta.env.VITE_STRIPE_SECRET_KEY; // FIXED — secrets live server-side only // frontend: import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY // backend route: process.env.STRIPE_SECRET_KEY (never VITE_-prefixed)
What our scanner does: the secrets check class (32 patterns on Pro: Stripe, AWS, OpenAI, Supabase, private keys, JWT) flags key material wherever it appears, and the exposure live-site checks verify nothing sensitive downloads from the deployed app.
2. Committed .env files
Bolt.new scaffolds .env files happily. If your prompt said "push to GitHub," check what's in the repo before you assume .gitignore did its job, models don't always add it.
What our scanner does: the exposure checks probe your deployed URL for /.env and /.git; the secrets class catches key-shaped values in pasted code.
3. String-to-code sinks: eval, new Function, timer strings
"Make the formula configurable" is all it takes. Models generate eval(), the Function constructor, or string arguments to setTimeout/setInterval far more often than you'd expect, three different spellings of arbitrary code execution.
// VULNERABLE — three flavors of the same bug
eval(`total(${discountExpr})`);
const fn = new Function("return " + userFilter);
setTimeout("update(" + rowId + ")", 500);
// FIXED
total(safeParseDiscount(discountExpr));
const fn = FILTERS[userFilter]; // allow-list, no codegen
setTimeout(() => update(rowId), 500);
What our scanner does: the eval usage, code injection, and setTimeout check classes flag every one of these sinks.
4. Tainted data: props and search params reaching sinks
Bolt.new apps pass data through long prop chains. A value that starts as a URL query param or form field can reach an HTML render, a fetch URL, or a database query several components later, and the model that wrote both ends never traced the path.
What our scanner does: taint tracking (Pro) performs data-flow analysis proving untrusted input reaches the sink, with no sanitizer in between. Findings where reachability is proven, not guessed, rank highest in the Top Risks list.
5. API routes that trust the client
Next.js route handlers generated by prompts like "add a delete endpoint" sometimes check isLoggedIn but not which user owns the record, broken access control in one prompt. The pattern: userId taken from the request body instead of the session.
// VULNERABLE — the client names the user
const { userId } = await req.json();
await db.orders.delete({ where: { id, userId } });
// FIXED — identity comes from the session, never the request body
const session = await getSession();
await db.orders.deleteMany({ where: { id, userId: session.user.id } });
What our scanner does: the SQL injection risk and taint classes flag untrusted input concatenated into queries; the advanced patterns engine (Pro) hunts second-order injection, where the payload is stored first and executed later.
6. The dependency list nobody audited
Bolt.new writes your package.json for you. Models invent package names ("slopsquatting") or pick lookalike spellings of real libraries. You ran npm install on whatever it wrote.
What our scanner does: SlopSquat Shield (Pro) verifies every import in your pasted code live against npm, hallucinated, newborn, and typosquat packages are flagged, with the real package the AI probably meant.
7. Headers and the deployed state
After deploy, check the security posture of what's actually live: Content-Security-Policy, clickjacking headers, TLS, and whether debug artifacts are reachable.
What our scanner does: the headers check class grades your live site's security headers, and the links class crawls same-domain pages for broken links that betray dead or debug endpoints.
The checklist
- ☐ No secret is
VITE_-prefixed or reachable from the browser - ☐
.envis gitignored and not deployed - ☐ No
eval,new Function, or string timer arguments - ☐ Every API route derives identity from the session, not the request
- ☐ Every npm package is real, established, and spelled correctly
- ☐ Security headers set on the deployed URL
- ☐ Every server route has auth, rate limiting, and input validation
8. Edge functions and server routes without rate limits
One more, because Bolt.new apps tend to grow server-side logic quietly. Prompts like "add an email endpoint" or "generate the PDF server-side" produce server routes and edge functions with no rate limiting, no auth check, and sometimes no input validation. They're reachable URLs that do expensive or privileged work for anyone who finds them.
The shape is always the same: a route handler that does exactly what the prompt asked, and nothing the prompt didn't ask. No session guard. No throttle. A PDF generator that takes arbitrary HTML input is a server-side request forgery waiting for a URL parameter. An email endpoint without a rate limit is a spam relay with your domain on it.
For every server route the model generated, check three things: who can call it (auth), how often (rate limit), and what the inputs can contain (validation). If the answer to any of the three is "the model didn't say," add it before deploy. These routes are the part of the app you never see in the preview, which is exactly why they ship unguarded.
What our scanner does: the advanced patterns engine (Pro) flags route handlers missing auth checks and highlights unvalidated inputs flowing into privileged operations, alongside the taint analysis from check 4.
Paste your Bolt.new code into Vibe-Code Audit and run all eight in one pass. Free tier, no card. Pro ($49 one-time, not a subscription) adds taint tracking, SlopSquat Shield, the full secret scan with rotation runbooks, and 16 advanced detector families.
Run the free pre-deploy scan →
FAQ
Do I scan the code or the deployed URL?
Code first, URL after. Paste the generated files before deploying to catch secrets and injection patterns; scan the live URL after deploying to verify headers, exposure probes, and the real deployed state.
Can the scanner read my whole repo?
Paste the files or code sections you want reviewed, the files that touch auth, payments, user input, and secrets deserve priority. There's no repo integration to configure.
What does taint tracking actually prove?
That a specific untrusted input (URL param, form field, header) flows to a specific dangerous sink (query, HTML render, eval) without passing through a sanitizer. It's data-flow analysis, not a keyword match, which is why it ranks as your top risk.
Is the Pro license really one-time?
Yes. Pro is $49 once, Team is $149 once. No subscription, no renewal, no per-scan metering.