Fix: Bolt × security
Bolt put your app in a browser tab.
Make sure your keys aren't in there too.
A securityscanner.dev audit found 15% of Bolt apps exposing hardcoded API keys in their frontend code. And exposed keys don't sit idle: bots scrape freshly deployed bundles within hours, and a leaked OpenAI key turns into someone else's usage bill. None of this means your product idea was wrong. It means the demo pattern shipped — and demos keep secrets in places production never can.
Why Bolt apps leak: the shortest path to a working demo
Bolt builds and runs your app inside WebContainers — everything executes in the browser, which is exactly why it feels instant. But that architecture nudges generated code toward client-side everything: when you ask Bolt to integrate OpenAI or Stripe, the fastest working version puts the key right in the frontend code, and that's frequently what you get. vibeappscanner.com documents the recurring vulnerabilities in almost every Bolt app it audits: exposed Supabase service_role keys, missing RLS policies, and bolted-on auth that renders a login screen without the API ever verifying who's calling. Unescaped user input adds stored XSS to the list. Each one is invisible in the preview. All of them are trivially findable by anyone who opens devtools on your deployed app.
The Bolt security checklist — run it before someone else does
Search your bundle for keys
Deploy, view source, search for 'sk-', 'sk_live', and 'service_role'. Bolt frequently hardcodes third-party keys in frontend files because that's how the demo worked. Every hit needs rotation, not just deletion.
The service_role key in client code
Supabase's service_role key bypasses every RLS policy. If it appears anywhere the browser can reach, your database has no access control at all — regardless of what policies you wrote.
Auth that only exists in the UI
A login page proves nothing. Call your API endpoints directly with curl, unauthenticated. If data comes back, your auth is decoration — Bolt often gates the interface without gating the API.
Unescaped user input
Bolt-generated components frequently render user content without sanitization. One stored XSS in a comment field means an attacker runs JavaScript in every other user's session.
Nothing slowing an attacker down
Try 30 rapid wrong-password logins against your own app. If nothing throttles you, credential stuffing runs at full speed against every account you have.
The wall: a server that refuses to start without its secrets
On useDeploy, secrets aren't scattered through source files — they live in environment variables, and a Zod schema validates all of them at boot. Miss one and the process exits with a named error instead of limping into production. And because secrets only exist server-side, the client bundle physically cannot leak what it never receives.
1 $ bun run start
2 ✗ Invalid environment:
3 BETTER_AUTH_SECRET Required
4 DATABASE_URL Required
5 error: process exited with code 1
6
7 # secrets are validated at boot, server-side only.
8 # the bundle can't leak what the client never receives.
What's already handled on the base
Boot-validated secrets
One Zod-validated env schema is the single home for every credential. Nothing secret is importable from client code, so 'key in the bundle' stops being a possible bug class.
Billing webhooks that survive replays
Payment webhooks are idempotent by externalOrderId on top of a durable outbox — a provider retrying the same event twice can't double-charge or double-credit anyone.
Signed outgoing webhooks
Webhooks your app sends are HMAC-signed, so receivers can verify they came from you — the discipline you want on both sides of the webhook pipe.
Rate limiting by tier
Read, write, and auth traffic each get their own limiter, with auth bucketed by both IP and email. The 30-wrong-passwords test from the checklist above hits a 429 here.
Isolation that isn't optional
Org-scoped repositories and a Prisma query guard make cross-tenant reads return 404. There is no equivalent of 'forgot to enable RLS' because there's no switch to leave off.
A test suite watching all of it
450+ automated tests plus a Playwright E2E gate in CI exercise the auth flows, webhook idempotency, and tenant boundaries on every merge.
Migration path: from WebContainer to a real backend
Export your project from Bolt — download the code or push it to GitHub. The React UI travels well; it's the everything-in-the-browser architecture that doesn't. The migration is mostly a relocation: every fetch that calls a third-party API with an embedded key becomes a call to your own typed endpoint, and the key moves to server-side env where the Zod schema validates it at boot. Business logic that lived in components becomes use cases behind Express controllers, typed end to end via the generated OpenAPI contract. Rotate every key that ever appeared in Bolt-generated source — assume all of them leaked — and do the move one integration at a time: OpenAI first if that's your burn risk, Stripe next, then the rest. Your users see the same app. Your keys stop being public.
Bolt × security, asked directly
My OpenAI key already leaked. What do I do first?+
Can I keep Supabase while I migrate?+
Does the base handle Stripe webhooks properly?+
Is this a rewrite?+
One license. Two ways to own it.
CORE
Founder
A frozen snapshot of UseDeploy. Yours forever, no updates.
- Frozen-version zip download
- Full source, commercial use, unlimited projects
- All 800+ tests · all docs pages
- 14-day refund
LATEST + UPDATES
Lifetime
Always the latest UseDeploy. Re-download every release, free.
- Latest-version zip — re-downloadable forever
- Every future release at no extra charge
- Priority Discord support
- All 800+ tests · all docs pages
- 14-day refund
Ship the app without shipping your keys
Keep the speed that got you here. Move onto a base where secrets are boot-validated, webhooks are idempotent, and 450+ tests guard the floor.