v0 and Next.js on Vercel: security checklist for AI-built apps
Apps generated by v0 (and many Cursor projects) are Next.js apps deployed to Vercel. Next.js gives you a real server, which is good news: secrets can stay server-side. The usual mistakes come from blurring that line.
Scan your live app free Passive, no signup, never touches your database.
1. Audit every NEXT_PUBLIC_ variable
Next.js inlines NEXT_PUBLIC_-prefixed environment variables into the JavaScript sent to the browser at build time. Only public values (Supabase URL and anon key, Stripe publishable key) should use the prefix. Rename anything secret and read it only in server code.
2. Keep secrets in server code only
Use secret env vars only in route handlers, server actions and server components. If a file has 'use client' at the top, nothing in it is secret.
3. Authorize every server action and route handler
Server actions and API routes can be called directly, without going through your UI. Check the session and the user's permission inside each one, not just in the page that shows the button.
4. Mark env vars as Sensitive on Vercel
Vercel supports sensitive environment variables whose values can't be read back after creation. Use them for API keys and database URLs.
5. Add security headers in next.config.js
Add HSTS, X-Frame-Options, nosniff and Referrer-Policy via headers() (snippet in our HSTS guide). A strict CSP for Next.js needs nonces; follow the Next.js CSP guide.
6. Keep browser source maps off
Next.js doesn't publish browser source maps unless productionBrowserSourceMaps is set to true. Leave it off.
7. Protect preview deployments
Preview URLs often run against real data. Use Vercel Deployment Protection so previews need a Vercel login.
8. Scan production
Run Unspill on your production URL to catch leaked keys, open CORS on API routes and missing headers.
Fix guides for these issues
- AI API key exposed: An OpenAI, Anthropic, Groq, OpenRouter or xAI key in your front-end bundle lets anyone run up your bill. Revoke it and proxy AI calls through a server function with rate limits.
- Stripe secret key exposed: A Stripe sk_live_ or sk_test_ key in your JavaScript lets anyone create charges, issue refunds and read your customers. Roll the key in the Stripe Dashboard and move payments server-side.
- Supabase service_role key exposed: A Supabase service_role (or sb_secret_) key in front-end code gives anyone full read/write access to your database, bypassing Row Level Security. Here is how to rotate it and fix the leak.
- Permissive CORS: If your API reflects any Origin or allows * with credentials, any website can read your users' data through their browser. Restrict CORS to your own domains.
- Content-Security-Policy: A Content-Security-Policy limits which scripts can run on your site, reducing the damage of XSS. Copy-paste CSP examples for Vercel, Netlify and Next.js apps using Supabase.
- HSTS: HSTS tells browsers to always use HTTPS for your domain, preventing downgrade attacks on public Wi-Fi. Add one header in vercel.json, _headers or next.config.js.
- Public source maps: Production .map files let anyone rebuild your original front-end code, comments and internal routes. Disable them in Vite or Next.js, or upload them privately to your error tracker.
FAQ
Are NEXT_PUBLIC_ variables visible to users?
Yes. Next.js inlines them into the client JavaScript at build time, so anyone can read them.
Can people call my server actions directly?
Yes. Treat every server action and route handler like a public API endpoint: authenticate and authorize inside it.
Sources
- Next.js docs: Environment variables
- Next.js docs: Data security
- Vercel docs: Sensitive environment variables
- Vercel docs: Deployment Protection
Last checked against these sources on 2026-10-19. Platforms change; when in doubt, the official docs win.