Security ⚑ Critical severity

SQL Injection via String Concat

User input concatenated directly into SQL strings lets attackers inject arbitrary SQL.

Concatenating user input directly into SQL strings lets attackers inject arbitrary SQL. The fix isn’t "sanitize the input" — any character can be weaponized. Parameterized queries (prepared statements) are the only real fix: the database driver separates query structure from data, so `‘ OR ‘1’=‘1’` is always just a string, never executable SQL.

❌ Vulnerable
// VULNERABLE — string concatenation
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  const query = `SELECT * FROM users WHERE username = '` + username + `' AND password = '` + password + `'`;
  // Attacker: username = "' OR '1'='1'; --"
  db.query(query, (err, result) => { /* ... */ });
});
✓ Fixed
// FIXED — parameterized query
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
  db.query(query, [username, password], (err, result) => { /* ... */ });
});
The OWASP Top 10 has listed SQL injection at #1 for years. Real cases: Django’s SQL injection via raw query in CVE-2022-21661, ClickHouse SQL injection in plugin upload system (CVE-2026-32306), MikroORM raw-query bypass.
PullLight flags template literal or `+` string concatenation inside SQL query functions (`.query()`, `db.execute()`, `SELECT`, `INSERT`, `UPDATE`, `DELETE` statements) where variables contain user input (`req.body`, `req.query`, `req.params`). It detects ORM raw query calls and flags unsafe string interpolation patterns in database operations.
See it in action — paste a diff into /analyze
Try a vulnerable example: pool.query(`SELECT * FROM users WHERE id = ${req.params.id}`)
Analyze a diff →