CASE FILE#6076WARNFiled 2026-04-13

Catching SQL Injection: Cursor and String-Interpolated Queries

Cursor writes a database query using direct string interpolation instead of parameterized inputs. SSG flags it at write time — string-interpolated SQL is the most common injection vector.

Case ID
#6076
Severity
WARN
Decision
BLOCK
Agent
Cursor
Category
Source Code

Correction note (2026-10-13). The per-call timings and latency figures that appeared in this article had no benchmark behind them and were removed. Sample output in this article is illustrative, not a recorded run. The only published measurement is p50 0.39 ms and p99 1.91 ms (sigmashake-bench daemon-socket run, 2026-06-10, ssg 0.29.156, n=500). Sub-2 ms evaluation is a design target.

Describe the task

You ask Cursor to write a user lookup query. The agent uses string template interpolation to build the SQL:

const query = `SELECT * FROM users WHERE email = '${email}'`;
const result = await db.query(query);

If email contains SQL metacharacters — ' OR '1'='1 — the query structure is modified and the attacker reads your entire users table. SSG's no-sql-injection write rule flags the file.

# illustrative sample output
[BLOCK] write_file › src/db/users.ts — rule: no-sql-injection
Reason: String-interpolated SQL query detected.

Give SSG context

SSG intercepts write calls via the SSG MCP Server integration inside Cursor and validates source code content.

Required context

rule no-sql-injection {
  enabled true
  priority 90
  severity error
  DENY write
  IF content REGEX "SELECT.*FROM.*WHERE.*\$\{"
  OR content REGEX "INSERT.*INTO.*VALUES.*\$\{"
  OR content REGEX "UPDATE.*SET.*\$\{"
  MESSAGE "String-interpolated SQL detected. Use parameterized queries or an ORM instead."
}

Optional context

Also catch template literal SQL building:

rule no-sql-concat {
  enabled true
  priority 90
  severity error
  DENY write
  IF content REGEX "(SELECT|INSERT|UPDATE|DELETE).*\+.*req\."
  MESSAGE "SQL query built with string concatenation from request data. Use parameterized queries."
}

What SSG does

SSG reads the full file content and runs the regex before saving. Cursor receives the block and can rewrite using parameterized queries.

Ask the agent to use parameterized queries

The SQL write was blocked: the query used string interpolation with user-supplied data.
Rewrite using parameterized queries:
  const result = await db.query("SELECT * FROM users WHERE email = $1", [email]);
Or use an ORM (Prisma, Drizzle, TypeORM) which handles parameterization automatically.

Suggest an ORM for new code

If the project already uses Prisma or another ORM, guide Cursor to use it:

Instead of raw queries, use Prisma:
  const user = await prisma.user.findUnique({ where: { email } });

Audit injection patterns across your codebase

After onboarding SSG, the first week's audit log often reveals historical write attempts with SQL injection patterns. Use this as a baseline security assessment.

How your regex handles different ORMs and drivers

The pattern targets template literal interpolation (${}) in SQL keywords. It doesn't match Prisma, Drizzle, or other ORMs that never build raw SQL strings this way. False positives are unlikely for parameterized patterns like db.query("SELECT...", [param]).

Check the rule against your data migration scripts

Some migrations legitimately use string-built SQL (e.g., dynamic schema changes). Add a path exclusion for your migrations directory if needed, combined with an ASK rule for human review.

Filed by Cursor
Engine ssg v1 · 2026-04-13
End of case file

Stop reading. Start governing.

Test a rule against any tool call right now. No install required.