no-unsafe-query
SQL injection is one of the most critical security vulnerabilities
Prevents SQL injection by detecting string concatenation or template literals with variables in
client.query()calls.
π¨ Security rule | π‘ Provides LLM-optimized guidance | β οΈ Set to error in recommended
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-89 (SQL Injection) |
| Severity | Critical (CVSS: 9.8) |
| Auto-Fix | β No auto-fix available |
| Category | Security |
| ESLint MCP | β Optimized for AI assistant integration |
| Best For | Protecting database operations from SQL injection vulnerabilities |
Value & investment case
Why this rule pays for itself. Framework:
cicd-impact/philosophy.md.
| Dimension | Value |
|---|---|
| CWE | CWE-89 β Improper Neutralization of Special Elements used in an SQL Command (CVSS 9.8 Critical) |
| Feedback-loop tier | Editor / pre-commit (sub-second) β cheapest layer per the feedback-loop hierarchy |
| Defensive-layer leverage | ~10Γ cheaper than unit-test Β· ~1,000Γ cheaper than production rollback Β· 10,000+Γ cheaper than disclosure β SQL injection is the most-cited OWASP A03 finding (cost-ratio anchors) |
| Niche relevance | Critical: fintech (regulatory + transaction data), healthtech (PHI), B2B SaaS (multi-tenant exposure), cybersecurity Β· High: marketplaces, infra/devtools Β· Medium: B2C |
| Investor-frame impact | SQL injection β full database disclosure β mandatory disclosure cycle. The most-cited single attack class in security-incident reports for two decades. Lint-time enforcement of parameterized queries is the cheapest possible structural defense. |
Read also: philosophy.md Β§investor-frame Β· niche-presets.json Β· analyzer-evaluation-framework.md
Rule Details
SQL injection is one of the most critical security vulnerabilities. This rule detects potentially unsafe SQL query construction in pg driver calls.
β Incorrect
// Template literal with variable
const result = await client.query(`SELECT * FROM users WHERE id = ${userId}`);
// String concatenation
const query = "SELECT * FROM users WHERE name = '" + userName + "'";
await pool.query(query);β Correct
// Parameterized query
const result = await client.query('SELECT * FROM users WHERE id = $1', [
userId,
]);
// Named parameters (with pg-named or similar)
const result = await client.query({
text: 'SELECT * FROM users WHERE id = $1',
values: [userId],
});Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
π CWE-89 OWASP:A05 CVSS:9.8 | SQL Injection detected | CRITICAL [SOC2,PCI-DSS,HIPAA,ISO27001]
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A05_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-89 OWASP:A05 CVSS:9.8 |
| Issue Description | Specific vulnerability | SQL Injection detected |
| Severity & Compliance | Impact assessment | CRITICAL [SOC2,PCI-DSS,HIPAA,ISO27001] |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Tagged Template Literals (sql...)
Why: Tagged templates like sql from libraries are function calls, not template literals.
// β NOT DETECTED - appears safe but may not be
import { sql } from 'some-library';
await client.query(sql`SELECT * FROM users WHERE id = ${userId}`);
// If 'sql' doesn't properly escape, this is vulnerable!Mitigation: Use a library verified to properly escape tagged templates.
Dynamic Query Variables
Why: When the query is stored in a variable, we can't analyze its construction.
// β NOT DETECTED
const unsafeQuery = buildQuery(userInput); // May concatenate strings internally
await client.query(unsafeQuery);Mitigation: Always use parameterized queries ($1, $2) directly in literals.
Nested Function Calls
Why: Queries passed through helper functions aren't traced.
// β NOT DETECTED
function executeQuery(query: string) {
return client.query(query);
}
executeQuery(`SELECT * FROM users WHERE id = ${userId}`);Mitigation: Apply the rule to helper functions that execute queries.
Format Functions with User Input
Why: The rule doesn't track data flow through pg-format or similar.
// β NOT DETECTED - but format() should handle escaping
import format from 'pg-format';
await client.query(format('SELECT * FROM %I.users', userSchema));
// Safe if format() escapes, but rule can't verifyMitigation: Use parameterized queries for values; use verified formatters only for identifiers.
When Not To Use It
- When using a query builder (Drizzle, Kysely) that handles parameterization
- In migration files with static SQL
Related Rules
- check-query-params - Validates parameter count
- no-batch-insert-loop - Prevents N+1 queries
If this rule caught a real vulnerability in your codebase, β star the repo β it keeps the detection logic maintained.
Did this rule catch something? Star the repo to get new CWE coverage as we ship it β or follow the AI-code-security benchmarks behind these rules.