Interlace ESLint
ESLint Interlace
PostgreSQLRules

no-unsafe-search-path

Prevents dynamic `SET search_path` queries that could enable schema hijacking.

Keywords: search_path, schema hijacking, CWE-426, pg, node-postgres, security

Prevents dynamic SET search_path queries that could enable schema hijacking.

⚠️ This rule errors by default in the recommended config.

Quick Summary

AspectDetails
CWE ReferenceCWE-426 (Untrusted Search Path)
SeverityHigh (CVSS: 7.5)
CategorySecurity

Rule Details

If an attacker controls the search_path, they can redirect function/table lookups to malicious schema objects.

❌ Incorrect

// Dynamic schema from user input
await client.query(`SET search_path TO ${userSchema}`);

// Template literal with variable
await pool.query(`SET search_path = ${schema}`);

// Concatenation
await client.query('SET search_path = ' + userSchema);

✅ Correct

// Static schema name
await client.query('SET search_path = public, my_schema');

// Safe: using pg-format with schema validation
if (!ALLOWED_SCHEMAS.includes(schema)) throw new Error('Invalid schema');
await client.query(format('SET search_path = %I', schema));

// Using validated schema from allowlist
const safeSchema = validateSchema(userInput); // throws if invalid
await client.query('SET search_path = $1', [safeSchema]);

Error Message Format

The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:

🔒 CWE-426 OWASP:A03 CVSS:7.5 | Untrusted Search Path detected | HIGH
   Fix: Review and apply the recommended fix | https://owasp.org/Top10/A03_2021/

Message Components

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-426 OWASP:A03 CVSS:7.5
Issue DescriptionSpecific vulnerabilityUntrusted Search Path detected
Severity & ComplianceImpact assessmentHIGH
Fix InstructionActionable remediationFollow the remediation steps below
Technical TruthOfficial referenceOWASP Top 10

When Not To Use It

  • For multi-tenant apps where schema is validated from a trusted source
  • In admin tools where schema input is fully controlled

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Query from Variable

Why: Query strings in variables are not analyzed.

// ❌ NOT DETECTED - SET search_path in variable
const searchPathQuery = `SET search_path = ${userSchema}`;
await client.query(searchPathQuery);

Mitigation: Use inline query strings. Define safe schema constants.

pg-format or Identifier Escaping

Why: pg-format's %I formatting looks like safe escaping but may still be vulnerable.

// ❌ NOT DETECTED (and may be safe) - pg-format used
import format from 'pg-format';
await client.query(format('SET search_path = %I', userSchema));
// ^^ pg-format doesn't validate schema existence

Mitigation: Validate schema against allowlist before using. Don't rely on escaping alone.

Multi-Tenant Schema Selection

Why: Complex tenant resolution logic is not understood.

// ❌ NOT DETECTED - Tenant-based schema
const schema = getTenantSchema(req.headers['x-tenant-id']);
await client.query(`SET search_path = ${schema}`);

Mitigation: Use centralized tenant schema resolver with allowlist validation.

Connection Pool Configuration

Why: search_path set in pool configuration is not checked.

// ❌ NOT DETECTED - search_path in pool options
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  options: `-c search_path=${userSchema}`, // Dynamic!
});

Mitigation: Validate pool configuration at startup. Use static search_path values.

On this page