8 Security Mistakes Cursor AI Makes (And How to Fix Them)
Why Cursor AI Has Security Blind Spots
Cursor AI is trained on millions of code examples — including millions of code examples with security flaws.
It optimizes for working code, not secure code. The result is a set of predictable, repeated security mistakes.
After scanning thousands of apps built with Cursor, we've identified the 8 most common patterns.
Mistake #1: Service Role Key Used Everywhere
What Cursor does: UsesSUPABASE_SERVICE_ROLE_KEY for all database operations because it "just works" — no permission errors.
Why it's dangerous: Bypasses all RLS policies. Any server-side bug becomes a full data breach.
Fix: Use the user's JWT token to create a scoped Supabase client:
const supabase = createClient(url, anonKey, {
global: { headers: { Authorization: Bearer ${userToken} } }
});
Mistake #2: CORS Set to Wildcard With Credentials
What Cursor does:Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true
Why it's dangerous: Any website can make authenticated requests on behalf of your users.
Fix: Restrict origins to your actual domains:
app.add_middleware(CORSMiddleware, allow_origins=["https://yourapp.com"])
Mistake #3: No Rate Limiting on Auth Endpoints
What Cursor does: Creates/api/auth/login with no rate limiting.
Why it's dangerous: Brute force attacks, credential stuffing, account enumeration.
Fix: Use Upstash Redis-based rate limiting or implement token bucket on the endpoint.
Mistake #4: User-Controlled IDs in Database Queries
What Cursor does:const { data } = await supabase
.from('documents')
.select('*')
.eq('id', params.id); // ← user-controlled, no ownership check
Why it's dangerous: IDOR (Insecure Direct Object Reference) — users can fetch other users' data by guessing IDs.
Fix: Always add .eq('user_id', session.user.id) to every query.
Mistake #5: Storing Secrets in localStorage
What Cursor does:localStorage.setItem('token', accessToken)
Why it's dangerous: XSS attacks can steal all localStorage data. JWT tokens in localStorage = session hijacking.
Fix: Use httpOnly cookies for sensitive tokens. Let your auth provider (Firebase, Supabase) handle token storage.
Mistake #6: SQL-Like Injection in Supabase RPC
What Cursor does:const { data } = await supabase.rpc('search_posts', {
query: userInput // ← unvalidated user input
});
Why it's dangerous: Even though Supabase uses parameterized queries by default, custom RPC functions often don't.
Fix: Validate and sanitize all inputs before passing to RPC functions. Use Zod schemas.
Mistake #7: Sensitive Data in URL Parameters
What Cursor does:/dashboard?userId=123&token=abc — puts sensitive identifiers in URLs.
Why it's dangerous: URLs appear in server logs, browser history, and Referrer headers. Tokens in URLs get leaked.
Fix: Use POST body or Authorization headers for sensitive data. Never put tokens in URLs.
Mistake #8: Missing Input Validation on File Uploads
What Cursor does: Accepts file uploads without validation:const file = req.file;
await storage.upload(file); // ← no type/size check
Why it's dangerous: Malicious file uploads, path traversal, storage cost attacks.
Fix:
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
if (!ALLOWED_TYPES.includes(file.mimetype)) throw new Error('Invalid file type');
if (file.size > 5 1024 1024) throw new Error('File too large');
How to Automatically Detect These
SecuriSky's scanner detects all 8 of these patterns automatically — including the ones hiding in your JavaScript bundles and Supabase configuration.
Run a free quick-scan at securisky.dev/scan/public, then sign up for the full 18-surface audit.