Overview
CVE-2026-33713 describes an authenticated SQL injection vulnerability in n8n's Data Table Get node. An attacker with permission to create or modify workflows could inject malicious SQL, potentially manipulating the database on SQLite (where single statements can be exploited) and, on PostgreSQL, triggering multi-statement executions that may modify or delete data. The issue has been fixed in n8n versions 1.123.26, 2.13.3, and 2.14.1; users should upgrade to one of these versions or newer to remediate. This vulnerability is classified under CWE-89 (SQL Injection) and demonstrates how untrusted input in dynamic queries can lead to unauthorized data access or modification.
Affected Versions
Before 1.123.26, 2.13.3, and 2.14.1 (vulnerable); fixed in 1.123.26, 2.13.3, and 2.14.1.
Code Fix Example
Node.js (Express) API Security Remediation
VULNERABLE (Node.js + Express):
const express = require('express');
const app = express();
const { Pool } = require('pg');
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
app.get('/records', async (req, res) => {
const { userId, orderByColumn } = req.query;
// Vulnerable: directly concatenating input into SQL, including orderByColumn
const sql = `SELECT id, name, created_at FROM records WHERE user_id = '${userId}' ORDER BY ${orderByColumn || 'id'} LIMIT 100;`;
try {
const { rows } = await pool.query(sql);
res.json(rows);
} catch (err) {
res.status(500).send('Error');
}
});
FIXED:
const express = require('express');
const app = express();
const { Pool } = require('pg');
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
app.get('/records', async (req, res) => {
const { userId, orderByColumn } = req.query;
// Safe: validate/whitelist columns and use parameterized query for user input
const allowed = ['id', 'name', 'created_at'];
const safeOrder = allowed.includes(orderByColumn) ? orderByColumn : 'id';
const sql = `SELECT id, name, created_at FROM records WHERE user_id = $1 ORDER BY ${safeOrder} LIMIT 100;`;
try {
const { rows } = await pool.query(sql, [userId]);
res.json(rows);
} catch (err) {
res.status(500).send('Error');
}
});