Overview
CVE-2026-41462 affects ProjeQtor versions 7.0 through 12.4.3, introducing an unauthenticated SQL injection vulnerability in the login flow. The attacker can supply crafted values in the login username field, concatenated directly into the SQL statement, to bypass authentication, create privileged accounts, read sensitive data, or, if the DB user has elevated permissions, execute operating system commands. This is a classic CWE-89 scenario where unsanitized input is concatenated into SQL. In real-world Node.js (Express) deployments, this means an attacker could gain session access or exfiltrate data without any credentials, compromising integrity and confidentiality of the application and its data. Upstream remediation requires both code fixes and lifecycle safeguards to prevent similar patterns in the future. You should treat this as a critical injection risk that demands patching and validation.
Affected Versions
ProjeQtor 7.0 through 12.4.3
Code Fix Example
Node.js (Express) API Security Remediation
const express = require('express');
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
const app = express();
app.use(express.json());
// Vulnerable: directly concatenating user input into SQL (insecure pattern)
app.post('/login', async (req, res) => {
const { username, password } = req.body;
const connection = await mysql.createConnection({ host: 'db', user: 'app', password: 'secret', database: 'appdb' });
// DO NOT DO THIS: vulnerable to SQL injection via username/password
const query = `SELECT id, password_hash FROM users WHERE username = '${username}' AND password_hash = '${password}'`;
try {
const [rows] = await connection.execute(query);
if (rows.length) {
res.json({ success: true, userId: rows[0].id });
} else {
res.status(401).json({ error: 'Invalid credentials' });
}
} finally {
await connection.end();
}
});
// Fixed: parameterized query with prepared statement and proper password handling
app.post('/login-fixed', async (req, res) => {
const { username, password } = req.body;
const connection = await mysql.createConnection({ host: 'db', user: 'app', password: 'secret', database: 'appdb' });
try {
// Use placeholders to prevent injection
const [rows] = await connection.execute(
'SELECT id, password_hash FROM users WHERE username = ?',
[username]
);
if (rows.length && await bcrypt.compare(password, rows[0].password_hash)) {
res.json({ success: true, userId: rows[0].id });
} else {
res.status(401).json({ error: 'Invalid credentials' });
}
} finally {
await connection.end();
}
});
app.listen(3000, () => console.log('Server running on port 3000'));