Injection

Injection in Node.js Express CVE-2026-32271 [CVE-2026-32271]

[Updated June 2026] Updated CVE-2026-32271

Overview

The CVE-2026-32271 case describes an SQL injection in Craft Commerce's TotalRevenue widget that allowed an authenticated admin user to trigger remote code execution via a four-step chain. In that PHP scenario, unsanitized widget settings were interpolated into SQL expressions and PDO's default multi-statement query support enabled an attacker to inject a malicious serialized PHP object into the queue, which when processed led to a gadget chain that could write a PHP webshell. The vulnerability could be exploited with just a few HTTP requests and did not require elevated privileges; the issues were fixed in versions 4.10.3 and 5.5.5. While this CVE is PHP-focused, the core risk-unsafe SQL construction and unsafe deserialization-maps to Node.js/Express as well. In Node.js/Express, similar patterns can arise when user-controlled data is concatenated into SQL statements or when deserialization paths process untrusted payloads. If an admin-configured widget, user input, or configuration data is interpolated into a query or passed through an unsafe deserialization step, an attacker could alter queries, exfiltrate data, or, in the worst case, achieve remote code execution through unsafe evaluation of payloads or gadget-like flows in libraries. The CVE highlights the importance of proper input handling and code-path isolation, which are equally critical in JavaScript runtimes. To fix such risks in Node.js/Express, adopt parameterized queries, use a query builder or ORM to avoid raw SQL concatenation, and disable multi-statement execution in the database driver. Validate and whitelist inputs for admin endpoints, avoid unsafe deserialization (prefer JSON with strict schemas and signatures), and enforce strict authentication/authorization for sensitive routes. Regularly patch dependencies and implement security tests that exercise edge cases around admin widget configuration and data handling.

Affected Versions

4.0.0-4.10.2, 5.0.0-5.5.4

Code Fix Example

Node.js (Express) API Security Remediation
/* Vulnerable pattern: building SQL from user input and enabling multi-statements */
const express = require('express');
const mysql = require('mysql2/promise');
const app = express();
app.use(require('body-parser').json());

const pool = mysql.createPool({
  host: 'localhost',
  user: 'app',
  password: 'secret',
  database: 'appdb',
  multipleStatements: true // vulnerable: allows stacked queries
});

app.post('/admin/widget/revenue', async (req, res) => {
  const { startDate, widgetFilter } = req.body; // widgetFilter comes from client
  const sql = `SELECT SUM(amount) AS total FROM orders WHERE date >= '${startDate}' AND ${widgetFilter};`;
  try {
    const [rows] = await pool.query(sql);
    res.json(rows);
  } catch (e) {
    res.status(500).send('Error');
  }
});

/* Fixed: parameterize values and whitelist dynamic parts, disable multi-statements */
const safePool = mysql.createPool({
  host: 'localhost',
  user: 'app',
  password: 'secret',
  database: 'appdb',
  multipleStatements: false
});

const allowedFilters = {
  all: '1=1',
  paid: `status = 'paid'`,
  pending: `status = 'pending'`
};

app.post('/admin/widget/revenue', async (req, res) => {
  const { startDate, filter } = req.body;
  const clause = allowedFilters[filter] ?? allowedFilters.all;
  const sql = `SELECT SUM(amount) AS total FROM orders WHERE date >= ? AND ${clause}`;
  try {
    const [rows] = await safePool.query(sql, [startDate]);
    res.json(rows);
  } catch (e) {
    res.status(500).send('Error');
  }
});

app.listen(3000, () => console.log('Server running'));

CVE References

Choose which optional cookies to allow. You can change this any time.