Skip to main content
interlace
Plugin: pgRules

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

AspectDetails
CWE ReferenceCWE-89 (SQL Injection)
SeverityCritical (CVSS: 9.8)
Auto-Fix❌ No auto-fix available
CategorySecurity
ESLint MCPβœ… Optimized for AI assistant integration
Best ForProtecting database operations from SQL injection vulnerabilities

Value & investment case

Why this rule pays for itself. Framework: cicd-impact/philosophy.md.

DimensionValue
CWECWE-89 β€” Improper Neutralization of Special Elements used in an SQL Command (CVSS 9.8 Critical)
Feedback-loop tierEditor / 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 relevanceCritical: fintech (regulatory + transaction data), healthtech (PHI), B2B SaaS (multi-tenant exposure), cybersecurity Β· High: marketplaces, infra/devtools Β· Medium: B2C
Investor-frame impactSQL 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

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-89 OWASP:A05 CVSS:9.8
Issue DescriptionSpecific vulnerabilitySQL Injection detected
Severity & ComplianceImpact assessmentCRITICAL [SOC2,PCI-DSS,HIPAA,ISO27001]
Fix InstructionActionable remediationFollow the remediation steps below
Technical TruthOfficial referenceOWASP 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 verify

Mitigation: 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

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.