no-unsafe-query
ESLint rule documentation for no-unsafe-query
📡 Live from GitHub — This documentation is fetched directly from no-unsafe-query.md and cached for 6 hours.
Prevents SQL injection by detecting string concatenation or template literals with variables in
client.query()calls.
SQL injection is one of the most critical security vulnerabilities
🚨 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 |
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