Cursor is different from Lovable or Bolt. It's a code editor, not a hosted app builder, so you pick the framework, the database, and the host. That's a lot of freedom. It also means there's no built-in "publish" screen that warns you about problems before your app goes live.
These are the checks I'd run before sharing an app built with Cursor. None of them need you to read code line by line. Most of them are one prompt plus one thing to look at.
1. Make sure your .env file never reached GitHub
Your .env file holds your keys. If it was ever committed to your repository, every key in it is readable by anyone who can see the repo, and it stays in the history even after you delete the file.
- Open your repository on GitHub and look for
.envin the file list. - Check that your
.gitignorefile lists.envand.env.*.
If you find one, deleting it isn't enough. Make new keys in each service and delete the old ones.
A side note: Cursor has a .cursorignore file that keeps files like .env out of what the AI agent reads. Cursor's docs are clear that it's not a security boundary, since terminal commands and tools can still read those files. It's useful, but it doesn't protect your keys from the internet.
Prompt for Cursor:
Make sure .env and .env.* are in .gitignore and not tracked by git. If a .env file was ever committed, list the keys that were in it so I can rotate them.
2. No secret behind a public prefix
This is the most common problem I see in apps built with any AI tool. In Next.js, any variable starting with NEXT_PUBLIC_ is copied into the JavaScript every visitor downloads. In Vite it's VITE_. A secret key with one of those prefixes is published, not hidden.
Prompt for Cursor:
List every environment variable that starts with NEXT_PUBLIC_ or VITE_. For any that holds a secret (OpenAI or other AI keys, Stripe secret key, database password, Supabase service_role or secret key), move it to a server-only variable and call that service from a server route instead.
There's a longer explanation of which keys are fine to show in How to hide API keys in a React app.
3. Every API route checks who's calling
Cursor is good at writing API routes that work. It's less consistent about routes that check who's allowed to use them. An API route with no login check lets anyone call it directly, without going through your app's buttons. That's how strangers read other users' data or run up an AI bill.
For each route, ask one question: what happens if a logged-out stranger calls this?
Prompt for Cursor:
Go through every API route and server action. Each one that reads or changes user data must check the signed-in user on the server and only return that user's data. Don't trust a user id sent from the browser. Add a basic rate limit to routes that call paid services like OpenAI or send email.
4. Database rules are on
If your app reads Supabase or Firebase from the browser, the database rules are the only thing between a stranger and your data. Cursor won't turn them on unless you ask.
- Supabase: every table needs row level security on, with policies limited to the row's owner. See Supabase row level security for beginners.
- Firebase: no rule should allow reads or writes for everyone, and test mode rules should be gone. See Firebase security rules for beginners.
5. Check your packages
AI tools install packages freely, and some of them have known security problems. If your project uses npm, run this in Cursor's terminal:
npm auditIt lists packages with known issues and how serious they are. You don't have to fix every low-severity item before launch. Do look at anything marked high or critical, and ask Cursor to update those packages and re-run your app to make sure nothing broke.
If you use GitHub, turning on Dependabot alerts in the repository's security settings will warn you about new ones after launch.
6. Security headers on your host
Security headers are small instructions your site sends to the browser, like "don't let other sites put me in a frame" and "only load scripts from here." Most hosts don't add them for you. The fix lives in your host's config: next.config, vercel.json, or a Netlify _headers file.
Prompt for Cursor:
Add these response headers to every page using my host's config: Content-Security-Policy (with frame-ancestors 'none'), Strict-Transport-Security, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, and Permissions-Policy. Make sure the Content-Security-Policy still allows the scripts my app needs.
The full walkthrough is in How to add security headers to your vibe-coded app.
7. Test it as a stranger
Code review only goes so far. The last check is to use your live app the way someone else would:
- Open a private browser window and sign up as a second person.
- Try to see the first account's data, including by changing an ID in the address bar.
- Log out and try to open pages that should need a login.
- Share your link in a message to yourself and check the preview looks right.
The short version
- No
.envin GitHub, and no secret behindNEXT_PUBLIC_orVITE_. - Every API route checks the signed-in user on the server.
- Database rules are on for every table.
npm auditshows nothing high or critical you haven't looked at.- Security headers are set, and a second account can't see the first one's data.
Code review looks at what you wrote. The free Throttle Bird scan looks at what actually got published: the page and JavaScript a visitor downloads, your headers, HTTPS, and, once you prove you own the app, whether your database answers a stranger. It never reads your repo. There's also a Cursor-specific checklist with more fix prompts.
Sources: Cursor: Ignore files, Next.js: Environment variables, Vite: Env variables, npm: npm audit.