Cursor-built app security checklist: keys, .cursorignore and what to review
Cursor writes code in your own repo, so you control where secrets live and what gets deployed. That's a strength, but generated code often takes the shortest path to working: a key in the front end, an API route without an auth check, a table without RLS. Use this list before each launch.
Scan your live app free Passive, no signup, never touches your database.
1. Keep secrets out of the agent's context
Cursor ignores files in .gitignore plus a default list that includes .env*. Add anything else sensitive (credentials.json, *.pem, *.key) to .cursorignore, or to the global ignore list in Cursor's settings. Cursor's docs note that the terminal and MCP tools the agent uses can't be blocked by .cursorignore, and that complete protection isn't guaranteed, so don't paste live keys into chat.
# .cursorignore (gitignore syntax)
**/.env
**/.env.*
**/credentials.json
**/secrets.json
**/*.pem
**/*.key2. Keep secrets out of git
Make sure .env and .env.* are in .gitignore before the first commit. If a key was ever committed, rotate it; deleting the file doesn't remove it from history.
3. Check what your bundler makes public
NEXT_PUBLIC_ (Next.js) and VITE_ (Vite) variables are inlined into JavaScript that browsers download. Only publishable values belong there: a Supabase URL and publishable/anon key, a Stripe pk_ key. Search your build output for secret prefixes:
# after building locally (Vite: dist/, Next.js: .next/static/)
grep -rEo "sk_(live|test)_[0-9A-Za-z]{10}|sk-proj-[0-9A-Za-z_-]{10}|sb_secret_[0-9A-Za-z_-]{6}|rk_(live|test)_[0-9A-Za-z]{10}|whsec_[0-9A-Za-z]{10}" dist/ .next/static/ 2>/dev/null4. Review every generated API route and server action
Ask: who can call this, and does it check that the record belongs to the caller? Generated handlers often trust an ID from the request body. Add authentication and ownership checks inside each handler, not just in the UI.
5. Lock down the database
If the browser talks to Supabase or Firebase directly, Row Level Security or Security Rules are your real access control. Use our Supabase RLS SQL or Firebase rules checklist.
6. Add security headers and turn off source maps
Add CSP, HSTS, X-Frame-Options, nosniff and Referrer-Policy at your host, and keep production browser source maps off (Next.js: productionBrowserSourceMaps stays false; Vite: build.sourcemap false).
7. Ask Cursor to review, then verify
A useful prompt: "List every place this codebase reads a secret, every API route and whether it checks auth and ownership, and every NEXT_PUBLIC_/VITE_ variable." Treat the answer as a lead to check, not a guarantee.
8. Scan the deployed app
Run Unspill on your production URL. It checks the files a visitor's browser downloads for leaked keys, exposed .env/.git, public source maps 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.
- Exposed .env file: If https://yourapp.com/.env downloads your environment file, every secret in it is public. Remove it from the deployed output, block dotfiles, and rotate every key.
- 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.
- 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.
- 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.
FAQ
Does Cursor read my .env file?
Per Cursor's docs, .env* files are on its default ignore list, along with anything in .gitignore and .cursorignore, so Agent, Tab and @-mentions can't access them. The docs also say the agent's terminal and MCP tools aren't blocked by .cursorignore and that protection isn't guaranteed.
Is code written by Cursor less secure?
Not inherently, but generated code tends to take the shortest path to working. Review secrets handling, auth checks and database rules before shipping, as you would for any code.
Sources
- Cursor docs: Ignore file
- Next.js docs: Environment variables
- Vite docs: Env variables
- Supabase docs: API keys
Last checked against these sources on 2026-10-19. Platforms change; when in doubt, the official docs win.