DEV Community

Cover image for Hardening the Data Layer: The node-postgres Engineering Standard
Ofri Peretz
Ofri Peretz

Posted on • Edited on • Originally published at ofriperetz.dev

Hardening the Data Layer: The node-postgres Engineering Standard

I've reviewed hundreds of Node.js + PostgreSQL codebases. The same vulnerability appears in 80% of them.

The Pattern That Looks Safe

// ❌ This looks fine, right?
async function getUser(userId) {
  const query = `SELECT * FROM users WHERE id = '${userId}'`;
  const result = await pool.query(query);
  return result.rows[0];
}
Enter fullscreen mode Exit fullscreen mode

It's clean. It's readable. It's also a critical security vulnerability.

The Attack

// Attacker input:
const userId = "'; DROP TABLE users; --";

// Generated query:
// SELECT * FROM users WHERE id = ''; DROP TABLE users; --'
Enter fullscreen mode Exit fullscreen mode

Your users table is gone. Your data is gone. Your job might be gone.

Why Developers Keep Making This Mistake

Reason Reality
"I validate the input" Validation can be bypassed
"It's an internal API" Internal APIs get exposed
"Template literals are safe" They're just string concatenation
"ORM handles this" Not if you use raw queries

The Correct Pattern

// βœ… Parameterized query - the ONLY safe pattern
async function getUser(userId) {
  const query = 'SELECT * FROM users WHERE id = $1';
  const result = await pool.query(query, [userId]);
  return result.rows[0];
}
Enter fullscreen mode Exit fullscreen mode

The $1 placeholder tells PostgreSQL to treat the value as data, not code. No amount of SQL injection can escape this.

Let ESLint Enforce This

npm install --save-dev eslint-plugin-pg
Enter fullscreen mode Exit fullscreen mode
// eslint.config.js
import pg from 'eslint-plugin-pg';
export default [pg.configs.recommended];
Enter fullscreen mode Exit fullscreen mode

Now run your linter:

src/users.ts
  4:17  error  πŸ”’ CWE-89 OWASP:A03 CVSS:9.8 | Unsafe query detected
               Fix: Use parameterized query: client.query('SELECT * FROM users WHERE id = $1', [userId])
Enter fullscreen mode Exit fullscreen mode

More Examples

❌ Dynamic table names

const table = userInput;
pool.query(`SELECT * FROM ${table}`); // SQL injection
Enter fullscreen mode Exit fullscreen mode

βœ… Allowlist tables

const ALLOWED_TABLES = ['users', 'orders', 'products'];
if (!ALLOWED_TABLES.includes(table)) throw new Error('Invalid table');
pool.query(`SELECT * FROM ${table}`); // Now safe
Enter fullscreen mode Exit fullscreen mode

❌ Building WHERE clauses

let query = 'SELECT * FROM users WHERE 1=1';
if (name) query += ` AND name = '${name}'`; // Injection!
Enter fullscreen mode Exit fullscreen mode

βœ… Build params array

const params = [];
let query = 'SELECT * FROM users WHERE 1=1';
if (name) {
  params.push(name);
  query += ` AND name = $${params.length}`;
}
await pool.query(query, params);
Enter fullscreen mode Exit fullscreen mode

Quick Install


bash
npm install --save-dev eslint-plugin-pg in 60 seconds. 15 rules.** PostgreSQL security. Connection management. Query optimization.

---
πŸ“¦ [npm: eslint-plugin-pg](https://www.npmjs.com/package/eslint-plugin-pg)
πŸ“– [Rule docs: no-unsafe-query](https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-pg/docs/rules/no-unsafe-query.md)

**[⭐ Star on GitHub](https://github.com/ofri-peretz/eslint)**

---

**The Interlace ESLint Ecosystem**
Interlace is a high-fidelity suite of static code analyzers designed to automate security, performance, and reliability for the modern Node.js stack. With over 330 rules across 18 specialized plugins, it provides 100% coverage for OWASP Top 10, LLM Security, and Database Hardening.

[Explore the full Documentation](https://eslint.interlace.tools)
---

Β© 2026 Ofri Peretz. All rights reserved.

---

**Build Securely.**
I'm Ofri Peretz, a Security Engineering Leader and the architect of the Interlace Ecosystem. I build static analysis standards that automate security and performance for Node.js fleets at scale.

[ofriperetz.dev](https://ofriperetz.dev) | [LinkedIn](https://linkedin.com/in/ofri-peretz) | [GitHub](https://github.com/ofri-peretz)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)