# How to find security issues using Cursor

- Tool: Cursor
- Difficulty: Intermediate
- Time required: 15-20 min
- Compatibility: Cursor Free+, any language with user input handling
- Last updated: March 2026

## TL;DR

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.

## Before you start

- 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

### 1. 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.

```
// Cursor Chat prompt (Cmd+L, Ask mode):
// @codebase Perform a security audit of this codebase.
// Find all instances of:
// 1. SQL queries built with string concatenation or
//    template literals using user input
// 2. User input rendered in HTML without escaping
// 3. User input passed to exec(), spawn(), or eval()
// 4. User input used in file paths (path traversal risk)
// 5. User input used in HTTP redirects without validation
//
// For each finding, list: file, line, risk level (High/
// 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.

### 2. 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.

```
---
description: Security rules for input handling
globs: "src/**/*.ts,src/**/*.tsx"
alwaysApply: true
---

## Input Security Rules
- NEVER concatenate user input into SQL queries — use parameterized queries
- NEVER use eval(), new Function(), or setTimeout with string arguments
- NEVER pass user input to child_process.exec() — use execFile with args array
- NEVER render user input as raw HTML — always escape or use textContent
- ALWAYS validate and sanitize user input at the API boundary
- ALWAYS use allowlists for redirect URLs, not blocklists
- ALWAYS validate file paths against a base directory (prevent path traversal)
- Use prepared statements for all database queries
- Use Content Security Policy headers in HTTP responses
```

**Expected result:** Cursor will avoid generating injection-vulnerable patterns in all future code.

### 3. 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.

```
// VULNERABLE (found by audit):
const result = await db.query(
  `SELECT * FROM users WHERE email = '${req.body.email}'`
);

// Select the vulnerable code, press Cmd+K:
// "Convert this to a parameterized query to prevent SQL
// injection. Use $1 placeholder syntax for PostgreSQL."

// FIXED:
const result = await db.query(
  'SELECT * FROM users WHERE email = $1',
  [req.body.email]
);
```

> 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.

### 4. 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.

```
// VULNERABLE (found by audit):
element.innerHTML = `<p>Welcome, ${userName}</p>`;

// Cmd+K prompt:
// "Fix this XSS vulnerability. Use textContent or a
// sanitization library instead of innerHTML."

// FIXED:
const p = document.createElement('p');
p.textContent = `Welcome, ${userName}`;
element.appendChild(p);
```

**Expected result:** User input is rendered safely without HTML interpretation.

### 5. 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.

```
// Cursor Chat prompt (Cmd+L, Ask mode):
// @codebase Re-run the security audit. Check specifically:
// 1. Are there any remaining SQL string concatenations
//    with user input?
// 2. Any innerHTML assignments with user-controlled data?
// 3. Any exec() calls with user input?
// 4. Any unvalidated redirect URLs?
// Report 'PASS' or list remaining issues.
```

**Expected result:** Cursor reports PASS for all checks, confirming the injection vulnerabilities have been resolved.

## Complete code example

File: `src/middleware/sanitize.ts`

```typescript
/**
 * Input sanitization middleware for Express routes.
 * Validates and sanitizes user input at the API boundary.
 */

import { Request, Response, NextFunction } from 'express';

// Allowlist of safe redirect domains
const ALLOWED_REDIRECT_HOSTS = [
  'myapp.com',
  'www.myapp.com',
];

export function sanitizeString(input: string): string {
  return input
    .replace(/[<>"'&]/g, (char) => {
      const entities: Record<string, string> = {
        '<': '&lt;', '>': '&gt;', '"': '&quot;',
        "'": '&#x27;', '&': '&amp;',
      };
      return entities[char] || char;
    })
    .trim();
}

export function validateRedirectUrl(url: string): boolean {
  try {
    const parsed = new URL(url);
    return ALLOWED_REDIRECT_HOSTS.includes(parsed.hostname);
  } catch {
    return false;
  }
}

export function preventPathTraversal(filePath: string, baseDir: string): string {
  const path = require('path');
  const resolved = path.resolve(baseDir, filePath);
  if (!resolved.startsWith(path.resolve(baseDir))) {
    throw new Error('Path traversal detected');
  }
  return resolved;
}

export function sanitizeMiddleware(
  req: Request, _res: Response, next: NextFunction
): void {
  if (req.body && typeof req.body === 'object') {
    for (const [key, value] of Object.entries(req.body)) {
      if (typeof value === 'string') {
        (req.body as Record<string, unknown>)[key] = sanitizeString(value);
      }
    }
  }
  next();
}
```

## Common mistakes

- **Only auditing routes and ignoring middleware, utilities, and background jobs** — Injection flaws can exist anywhere user input flows, including message queue handlers, cron jobs, and utility functions called from multiple places. Fix: Use @codebase in your audit prompt to search the entire src/ directory, not just routes or controllers.
- **Using blocklists instead of allowlists for input validation** — Blocklists (blocking known-bad patterns) can always be bypassed with new encoding tricks. Allowlists (permitting only known-good patterns) are inherently safer. Fix: Add to .cursorrules: 'Use allowlists for redirect URLs, file paths, and input patterns. Never use blocklists.'
- **Sanitizing output instead of validating input** — Output encoding helps but does not prevent the malicious data from entering your database. Validate and reject bad input at the boundary. Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/cursor-tutorial/how-to-prompt-cursor-ai-to-identify-and-flag-potential-injection-flaws-in-user-input-code
© RapidDev — https://www.rapidevelopers.com/cursor-tutorial/how-to-prompt-cursor-ai-to-identify-and-flag-potential-injection-flaws-in-user-input-code
