Cursor can act as a security auditor when prompted correctly, identifying SQL injection, XSS, command injection, and other input-based vulnerabilities in your code. This tutorial shows how to use @codebase searches, targeted security prompts, and .cursorrules to make Cursor flag and fix injection flaws before they reach production.
Finding security issues in your code with Cursor
Injection attacks remain the top web application security risk. Cursor's ability to analyze code patterns across your entire codebase makes it an effective tool for identifying unsanitized inputs, raw SQL concatenation, unescaped HTML output, and command injection risks. This tutorial teaches you how to run security audits with Cursor and fix the issues it finds.
Prerequisites
- Cursor installed with a web application project
- Code that handles user input (forms, APIs, URL parameters)
- Basic understanding of common injection attacks (SQL, XSS, command)
- Familiarity with Cursor Chat (Cmd+L) and @codebase search
Step-by-step guide
Run a codebase-wide injection audit
Run a codebase-wide injection audit
Start with a broad scan using Cursor's @codebase context to find all places where user input is used without sanitization. This gives you a prioritized list of potential vulnerabilities.
1// Cursor Chat prompt (Cmd+L, Ask mode):2// @codebase Perform a security audit of this codebase.3// Find all instances of:4// 1. SQL queries built with string concatenation or5// template literals using user input6// 2. User input rendered in HTML without escaping7// 3. User input passed to exec(), spawn(), or eval()8// 4. User input used in file paths (path traversal risk)9// 5. User input used in HTTP redirects without validation10//11// For each finding, list: file, line, risk level (High/12// Medium/Low), the vulnerable pattern, and a fix suggestion.Expected result: A categorized list of potential injection vulnerabilities across your codebase with severity ratings and fix suggestions.
Add security rules to .cursor/rules
Add security rules to .cursor/rules
Create rules that prevent Cursor from generating vulnerable code in the first place. These rules act as guardrails for all future code generation.
1---2description: Security rules for input handling3globs: "src/**/*.ts,src/**/*.tsx"4alwaysApply: true5---67## Input Security Rules8- NEVER concatenate user input into SQL queries — use parameterized queries9- NEVER use eval(), new Function(), or setTimeout with string arguments10- NEVER pass user input to child_process.exec() — use execFile with args array11- NEVER render user input as raw HTML — always escape or use textContent12- ALWAYS validate and sanitize user input at the API boundary13- ALWAYS use allowlists for redirect URLs, not blocklists14- ALWAYS validate file paths against a base directory (prevent path traversal)15- Use prepared statements for all database queries16- Use Content Security Policy headers in HTTP responsesExpected result: Cursor will avoid generating injection-vulnerable patterns in all future code.
Fix SQL injection vulnerabilities
Fix SQL injection vulnerabilities
For each SQL injection finding, select the vulnerable code, press Cmd+K, and ask Cursor to convert it to parameterized queries. Reference your database library so Cursor uses the correct parameterization syntax.
1// VULNERABLE (found by audit):2const result = await db.query(3 `SELECT * FROM users WHERE email = '${req.body.email}'`4);56// Select the vulnerable code, press Cmd+K:7// "Convert this to a parameterized query to prevent SQL8// injection. Use $1 placeholder syntax for PostgreSQL."910// FIXED:11const result = await db.query(12 'SELECT * FROM users WHERE email = $1',13 [req.body.email]14);Pro tip: For bulk fixes, use Composer (Cmd+I): '@src/routes/ Convert all SQL string concatenations to parameterized queries. Process one file at a time.'
Expected result: All SQL queries use parameterized syntax with no string concatenation of user input.
Fix XSS vulnerabilities
Fix XSS vulnerabilities
Address cross-site scripting risks where user input is rendered as HTML. Ask Cursor to replace dangerous patterns like innerHTML with safe alternatives.
1// VULNERABLE (found by audit):2element.innerHTML = `<p>Welcome, ${userName}</p>`;34// Cmd+K prompt:5// "Fix this XSS vulnerability. Use textContent or a6// sanitization library instead of innerHTML."78// FIXED:9const p = document.createElement('p');10p.textContent = `Welcome, ${userName}`;11element.appendChild(p);Expected result: User input is rendered safely without HTML interpretation.
Re-run the audit to verify fixes
Re-run the audit to verify fixes
After fixing the identified vulnerabilities, run the security audit prompt again to confirm all issues are resolved. This creates a verification loop that catches any remaining problems.
1// Cursor Chat prompt (Cmd+L, Ask mode):2// @codebase Re-run the security audit. Check specifically:3// 1. Are there any remaining SQL string concatenations4// with user input?5// 2. Any innerHTML assignments with user-controlled data?6// 3. Any exec() calls with user input?7// 4. Any unvalidated redirect URLs?8// Report 'PASS' or list remaining issues.Expected result: Cursor reports PASS for all checks, confirming the injection vulnerabilities have been resolved.
Complete working example
1/**2 * Input sanitization middleware for Express routes.3 * Validates and sanitizes user input at the API boundary.4 */56import { Request, Response, NextFunction } from 'express';78// Allowlist of safe redirect domains9const ALLOWED_REDIRECT_HOSTS = [10 'myapp.com',11 'www.myapp.com',12];1314export function sanitizeString(input: string): string {15 return input16 .replace(/[<>"'&]/g, (char) => {17 const entities: Record<string, string> = {18 '<': '<', '>': '>', '"': '"',19 "'": ''', '&': '&',20 };21 return entities[char] || char;22 })23 .trim();24}2526export function validateRedirectUrl(url: string): boolean {27 try {28 const parsed = new URL(url);29 return ALLOWED_REDIRECT_HOSTS.includes(parsed.hostname);30 } catch {31 return false;32 }33}3435export function preventPathTraversal(filePath: string, baseDir: string): string {36 const path = require('path');37 const resolved = path.resolve(baseDir, filePath);38 if (!resolved.startsWith(path.resolve(baseDir))) {39 throw new Error('Path traversal detected');40 }41 return resolved;42}4344export function sanitizeMiddleware(45 req: Request, _res: Response, next: NextFunction46): void {47 if (req.body && typeof req.body === 'object') {48 for (const [key, value] of Object.entries(req.body)) {49 if (typeof value === 'string') {50 (req.body as Record<string, unknown>)[key] = sanitizeString(value);51 }52 }53 }54 next();55}Common mistakes when findding security issues using Cursor
Why it's a problem: Only auditing routes and ignoring middleware, utilities, and background jobs
How to avoid: Use @codebase in your audit prompt to search the entire src/ directory, not just routes or controllers.
Why it's a problem: Using blocklists instead of allowlists for input validation
How to avoid: Add to .cursorrules: 'Use allowlists for redirect URLs, file paths, and input patterns. Never use blocklists.'
Why it's a problem: Sanitizing output instead of validating input
How to avoid: Apply both: validate input at the API boundary AND escape output during rendering. Ask Cursor to implement both layers.
Best practices
- Run Cursor security audits regularly, not just once, as new code can introduce new vulnerabilities
- Add security rules to .cursor/rules so Cursor never generates vulnerable patterns
- Use @codebase for comprehensive audits that cover all files, not just the ones you think are risky
- Apply fixes with Cmd+K on selected vulnerable code for precise, reviewable changes
- Use parameterized queries for all database operations, no exceptions
- Validate all user input at the API boundary with allowlist-based rules
- Test fixes by re-running the audit prompt to verify all issues are resolved
- Reference OWASP Top 10 in your .cursorrules so Cursor understands the full threat model
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Audit this Express.js API for injection vulnerabilities. Check for: SQL injection (string concatenation in queries), XSS (innerHTML with user input), command injection (exec with user data), path traversal (unsanitized file paths), and open redirects. For each finding, provide the file, line, severity, and a code fix using parameterized queries, textContent, execFile, path.resolve validation, or URL allowlists.
In Cursor Chat (Cmd+L): @codebase @.cursor/rules/security.mdc Perform a full security audit of this codebase. Find all user input that reaches SQL queries, HTML rendering, exec/spawn calls, file system operations, or HTTP redirects without proper sanitization. Prioritize by severity. Show the fix for each High-severity finding.
Frequently asked questions
Can Cursor reliably find all injection vulnerabilities?
Cursor catches common patterns like string concatenation in SQL and innerHTML with user data. It may miss complex data flows where user input passes through multiple functions before reaching a vulnerable sink. Use dedicated SAST tools alongside Cursor for comprehensive security.
Should I use Cursor's security audit instead of a SAST tool?
No. Use Cursor for quick, iterative checks during development and a proper SAST tool (Snyk, Semgrep, SonarQube) in your CI/CD pipeline. Cursor is a complement, not a replacement for dedicated security tooling.
How often should I run security audits with Cursor?
Run a quick audit after every major feature addition or when onboarding new team members. The @codebase audit prompt takes about 30 seconds and catches most common issues.
Will .cursorrules prevent all injection vulnerabilities in generated code?
Rules significantly reduce injection patterns but are not foolproof. Rules can be ignored in long sessions, and complex patterns may slip through. Always review generated code that handles user input, even with rules in place.
Can Cursor help with security in non-JavaScript projects?
Yes. Cursor understands injection patterns across languages. For Python, it checks for f-string SQL queries and Jinja2 template injection. For Go, it checks for fmt.Sprintf in SQL and os/exec usage. Specify your language in the audit prompt.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation