Bolt, v0 and Replit app security
Each AI builder produces a slightly different kind of app, so each one tends to leak in slightly different places. Here's where to look for each, plus the checks that apply to all of them.
The shared problem
Whatever tool you used, three facts hold:
- Frontend code is public. Everything shipped to the browser can be read by anyone.
- Public env prefixes publish values.
VITE_(Vite docs) andNEXT_PUBLIC_(Next.js docs) variables end up in the JavaScript bundle. - The database has to enforce access. If the browser talks to Supabase or another backend directly, the rules have to live in the database, not the UI. The CVE-2025-48757 write-up shows what happens when they don't.
What changes between tools is the default architecture, and so the most likely mistake.
Bolt (bolt.new)
Typical shape: Bolt projects are often Vite + React single-page apps, frequently paired with Supabase, deployed as static files.
Where it leaks: because a static SPA has no server of its own, any API call the app makes, it makes from the browser. When you ask for "add AI chat" or "add Stripe checkout", the shortest path is a VITE_OPENAI_API_KEY or VITE_STRIPE_SECRET_KEY used straight from a component. That key is now public.
How to check: search your project for VITE_ and read every variable name. Anything with SECRET, PRIVATE, SERVICE_ROLE or a provider's secret key is a leak. Then search your live site's JavaScript for sk_live_, sk- and service_role.
This is a Vite app. Find every VITE_ environment variable that holds a secret (API secret keys, service_role keys, tokens). Move the code that uses each one into a server-side function (a Supabase Edge Function or a serverless function on my host), store the secret there without the VITE_ prefix, and have the frontend call that function. Then list which keys I need to rotate.
Also check: that your deploy publishes only the dist folder, and that /.env on your live domain doesn't return your variables.
v0 (by Vercel)
Typical shape: v0 generates Next.js and React code, usually deployed on Vercel.
Where it leaks: Next.js gives you a real server (Server Components, Route Handlers, Server Actions), which is great: secrets can stay there. The mistakes are (a) putting a secret in a NEXT_PUBLIC_ variable to get rid of an "undefined" error in a client component, and (b) importing server code that reads a secret into a file marked "use client".
How to check: in your Vercel project's environment variables, read every NEXT_PUBLIC_ name. Search your code for process.env inside files that start with "use client". Then search the live site's JavaScript for secret key prefixes.
This is a Next.js app. Make sure no secret is in a NEXT_PUBLIC_ variable or read inside a "use client" file. Move secret-using code into Route Handlers or Server Actions, add the "server-only" package import to modules that read secrets so they can't be bundled into client code, and check the user's session inside each Server Action before doing anything.
Also check: Server Actions and Route Handlers are public endpoints. Anyone can call them directly, so each one needs its own auth check. Headers like CSP and HSTS can be added in next.config.js or vercel.json.
Replit
Typical shape: Replit apps vary widely, but often include a real backend (Node, Python) alongside a frontend, with credentials stored in Replit's Secrets tool and exposed to your code as environment variables.
Where it leaks: Secrets keep keys out of your source files, but they don't control where the value goes next. If a backend route returns a config object that includes a secret, or the frontend build reads a secret through a VITE_ variable, the value still ends up in the browser. Another common one: debug or admin routes left open without authentication.
How to check: open your deployed app, go to the Network tab, and look at the JSON your own API returns, especially config, settings or "me" endpoints. Search the live JavaScript for secret key prefixes. List your backend routes and confirm each sensitive one checks who's calling.
Review every backend route in this app. For each one tell me whether it requires authentication, and add an auth check to any route that reads or changes user data or calls a paid API. Make sure no route returns environment variables, secrets or full config objects to the client, and remove any debug or test routes.
Cursor and other AI editors
With Cursor or a similar editor you can build anything, so the risks depend on your stack. The same checks apply. One addition: AI edits across many files at once, so review diffs that touch .env files, auth middleware, RLS policies or CORS settings before accepting them.
Checks for every tool
curl -sI https://yourapp.com # CSP, HSTS, X-Frame-Options, nosniff present?
curl -sI http://yourapp.com # 301/308 to https?
curl -s https://yourapp.com/.env # must not show KEY=value lines
curl -s https://yourapp.com/.git/HEAD # must not show "ref: refs/heads/..."
For my host, add Strict-Transport-Security, X-Content-Type-Options: nosniff, X-Frame-Options: DENY and a Content-Security-Policy that only allows the domains my app uses. Force HTTPS with a 301 redirect, and block any request for /.env or /.git.
If you use Supabase with any of these tools, also work through the RLS checker. The full list lives in the vibe coding security checklist.