Security Checklist for Apps Built with Cursor
Why Cursor Apps Need a Security Checklist
Cursor is one of the best AI coding tools available. It writes clean, functional code fast. But it optimizes for "it works" — not "it's secure." Every Cursor-built app should go through a security checklist before shipping to production.
Here's the checklist we use at VibeSafe, based on scanning thousands of AI-generated apps.
The Checklist
API Keys & Secrets
- [ ] No API keys hardcoded in client-side files
- [ ] No
NEXT_PUBLIC_prefix on secret keys (Supabase service_role, Stripe secret, etc.) - [ ]
.envfile is in.gitignore - [ ] No secrets in git history (check with
git log --all -p | grep -i "sk_live\|service_role\|secret") - [ ] Third-party API keys (OpenAI, Stripe, Resend) are only used in server-side code
Authentication
- [ ] All API routes check for a valid session/token
- [ ] Admin routes have role-based access control
- [ ] Password reset tokens expire
- [ ] OAuth redirect URIs are restricted to your domain
- [ ] No user data returned in error messages
Security Headers
- [ ]
Strict-Transport-Security(HSTS) is set - [ ]
X-Content-Type-Options: nosniffis set - [ ]
X-Frame-Options: DENYprevents clickjacking - [ ]
Content-Security-Policyrestricts script sources - [ ]
Referrer-Policyis set tostrict-origin-when-cross-origin - [ ]
Permissions-Policyrestricts camera, microphone, geolocation
CORS
- [ ] No wildcard
Access-Control-Allow-Origin: * - [ ] Allowed origins are explicitly listed
- [ ] Credentials are not allowed with wildcard origins
Database
- [ ] Row Level Security (RLS) is enabled on all Supabase tables
- [ ] No raw SQL queries with user input (use parameterized queries)
- [ ] Database connection strings are not in client code
- [ ] Supabase service_role key is server-only
Payments
- [ ] Stripe secret key (
sk_live_*) is never in client code - [ ] Webhook signatures are verified
- [ ] Price IDs are validated server-side (not trusted from the client)
- [ ] Subscription status is checked server-side before granting access
Infrastructure
- [ ] HTTPS is enforced (HTTP redirects to HTTPS)
- [ ] Rate limiting is configured on auth and API endpoints
- [ ] Error pages don't leak stack traces or internal paths
- [ ] File upload endpoints validate file type and size
Common Cursor Mistakes
1. Using the OpenAI key in a client component
Cursor often generates React components that call the OpenAI API directly:
// BAD — Cursor generated this in a client component
const response = await fetch("https://api.openai.com/v1/chat/completions", {
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPENAI_API_KEY}`,
},
});
Fix: Move API calls to a Next.js route handler (app/api/chat/route.ts) and call it from the client.
2. Missing auth checks on API routes
Cursor creates API routes that work, but it rarely adds auth checks:
// BAD — no auth check
export async function POST(req: Request) {
const { userId, data } = await req.json();
await db.update(userId, data); // Anyone can update any user
}
Fix: Always verify the session before processing the request.
3. CORS wildcard in middleware
// BAD — allows any origin
response.headers.set("Access-Control-Allow-Origin", "*");
Fix: Set specific allowed origins.
Automate It
Instead of manually checking everything, run a VibeSafe scan on your deployed URL. It checks all of the above in under 60 seconds and gives you a prioritized list of what to fix.