HIGH sql injectionexpress

Sql Injection in Express

How Sql Injection Manifests in Express

SQL Injection in Express applications typically occurs when user input is directly interpolated into SQL queries without proper sanitization. Express's minimalist design means developers must explicitly handle database interactions, creating multiple opportunities for injection vulnerabilities.

The most common pattern involves concatenating user input into query strings:

const express = require('express');
const app = express();
app.use(express.json());

app.get('/users/:id', (req, res) => {
const userId = req.params.id;
const query = `SELECT * FROM users WHERE id = ${userId}`;
db.query(query, (err, results) => {
if (err) throw err;
res.json(results);
});

An attacker can exploit this by requesting /users/1 OR 1=1, causing the query to return all users. More sophisticated attacks might use 1; DROP TABLE users; to delete data.

Express middleware patterns can also introduce injection risks. Consider this example using dynamic table names:

app.get('/data/:table', (req, res) => {
const table = req.params.table;
const query = `SELECT * FROM ${table} LIMIT 10`;
db.query(query, (err, results) => {
res.json(results);
});

This allows attackers to access any table in your database by manipulating the URL parameter.

Object-relational mapping (ORM) libraries like Sequelize don't automatically prevent injection if used incorrectly. This vulnerable pattern bypasses parameterization:

app.post('/search', (req, res) => {
const { name } = req.body;
const query = `SELECT * FROM products WHERE name LIKE '%${name}%'`;
sequelize.query(query).then(results => {
res.json(results);
});

Even with ORM libraries, developers sometimes fall back to raw queries for complex operations, reintroducing injection risks.

Express-Specific Detection

Detecting SQL Injection in Express applications requires examining both the code structure and runtime behavior. middleBrick's black-box scanning approach tests unauthenticated endpoints for injection vulnerabilities without requiring source code access.

The scanner automatically identifies Express route patterns and tests for SQL injection by injecting payloads into URL parameters, query strings, and request bodies. For the vulnerable endpoint:

app.get('/users/:id', (req, res) => { ... })

middleBrick would test payloads like:

  • 1 OR 1=1 - tests boolean logic injection
  • 1' OR '1'='1 - tests string-based injection
  • 1; DROP TABLE users - tests command chaining
  • 1 ORDER BY 1-- - - tests for error-based detection

The scanner analyzes HTTP responses for SQL error messages, unexpected data volumes, or execution time changes that indicate successful injection.

For Express applications using template engines like Pug or EJS for dynamic SQL generation, middleBrick examines template files for unsafe interpolation patterns. The scanner also checks for common Express middleware configurations that might expose database credentials or connection details.

middleBrick's OpenAPI analysis complements black-box scanning by examining your API specification for parameters that map to database operations. When it finds endpoints with type: string parameters used in database queries, it prioritizes those for injection testing.

The CLI tool provides detailed findings with specific payloads that triggered vulnerabilities:

middlebrick scan https://api.example.com/users/1
SQL Injection detected in GET /users/:id
Severity: HIGH
Response: 200 OK (unexpected data volume)
Recommendation: Use parameterized queries

GitHub Action integration allows continuous monitoring of API endpoints as part of your deployment pipeline, catching injection vulnerabilities before production release.

Express-Specific Remediation

Express applications should use parameterized queries exclusively for database operations. Here's the secure version of the vulnerable example:

const express = require('express');
const app = express();
app.use(express.json());

const mysql = require('mysql2/promise');
const db = mysql.createPool({...});

app.get('/users/:id', async (req, res) => {
try {
const [rows] = await db.execute(
'SELECT * FROM users WHERE id = ?'
, [req.params.id]);
res.json(rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Database error' });
}

Notice the use of ? placeholders and passing parameters as an array. This prevents any user input from being interpreted as SQL code.

For Sequelize, use the built-in query methods with proper parameterization:

app.post('/search', async (req, res) => {
try {
const { name } = req.body;
const results = await sequelize.query(
'SELECT * FROM products WHERE name LIKE :name',
{ replacements: { name: `%${name}%` }, type: sequelize.QueryTypes.SELECT }
);
res.json(results);
} catch (err) {
res.status(500).json({ error: 'Search failed' });
}

Express middleware can enforce input validation before database queries reach the application logic:

const { body, param } = require('express-validator');

app.post('/users', [

body('email').isEmail(),
body('age').isInt({ min: 0, max: 120 }),
(req, res) => {
// Validated data is safe to use in queries
}
]);

For dynamic table access (which should generally be avoided), validate against a whitelist:

const validTables = ['users', 'products', 'orders'];

app.get('/data/:table', (req, res) => {
const table = req.params.table;
if (!validTables.includes(table)) {
return res.status(400).json({ error: 'Invalid table' });
}

db.query(`SELECT * FROM ${table} LIMIT 10`, (err, results) => {
res.json(results);
});

While this example still uses string interpolation for table names, the whitelist validation prevents arbitrary table access. For production, consider using a mapping from safe identifiers to actual table names.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can ORM libraries like Sequelize prevent SQL Injection in Express?
ORMs provide protection when used correctly with their built-in query methods and parameterization features. However, they don't automatically prevent injection if you use raw queries with string concatenation or bypass the ORM's safety mechanisms. Always use parameterized queries even with ORMs, and never concatenate user input directly into SQL strings.
How does middleBrick detect SQL Injection without access to my source code?
middleBrick uses black-box scanning to test your API endpoints by sending various SQL injection payloads to URL parameters, query strings, and request bodies. It analyzes HTTP responses for indicators like SQL error messages, unexpected data volumes, or timing changes that suggest successful injection. The scanner also examines your OpenAPI specification to identify parameters that likely interact with databases and prioritizes those for testing.