CVE-2026-110910 in ljharb
Résumé
par VulDB • 27/10/2026
### Résumé
L'utilisation de `qs.stringify` avec l'option `allowEmptyArrays: true` écrit la clé d'un tableau vide sans l'encoder, bien que les clés soient encodées par défaut. Une clé contenant le caractère `&` (ou le délimiteur configuré), `=` ou `#` ∴ devient de la syntaxe de chaîne de requête au lieu de données ; ainsi, un nom de clé fourni par l'appelant peut ajouter des paramètres à la chaîne de requête sérialisée ou la tronquer.
### Détails
Dans `lib/stringify.js`, la branche `allowEmptyArrays` effectue un retour anticipé en renvoyant `adjustedPrefix + '[]'`, avant le code qui fait passer toutes les autres clés par l'encodeur et le formateur. Ainsi, `{ "x&k=v": ["1"] }` est sérialisé sous la forme `x%26k%3Dv%5B0%5D=1`, mais `{ "x&k=v": [] }` est sérialisé sous la forme `x&k=v[]`. Ce retour anticipé s'applique à n'importe quelle profondeur (`{ "a": { "b&k=v": [] } }` donne `a[b&k=v][]`), quel que soit le format de tableau, avec l'option `allowDots` activée et avec un encodeur personnalisé (qui n'est jamais appelé pour cette clé). Avec les options `encode: false` ou `encodeValuesOnly: true`, les clés sont intentionnellement laissées sans encodage sur tous les chemins ; ces configurations ne sont pas affectées.
#### PoC
```js var qs = require("qs");
var query = qs.stringify({ q: "hi", "x&apiKey=evil&y": [] }, { allowEmptyArrays: true });
// "q=hi&x&apiKey=evil&y[]"
qs.parse(query);
// { q: 'hi', x: '', apiKey: 'evil', y: [''] }
qs.stringify({ "x#": [], z: "1" }, { allowEmptyArrays: true });
// "x#[]&z=1" : dans une URL, tout ce qui suit le caractère "#" devient la fragment
```
#### Correction
Appliquée dans le commit 234d505 sur `main` et publiée en tant que v6.17.0 : la clé d'un tableau vide passe désormais par l'encodeur et le formateur exactement comme n'importe quelle autre valeur, de sorte que `{ "x&apiKey=evil&y": [] }` est maintenant sérialisé sous la forme `x%26apiKey%3Devil%26y[]`. Les clés qui ne nécessitent pas d'encodage sont sérialisées comme auparavant, à deux exceptions correspondant aux autres chemins : les crochets d'une clé imbriquée sont désormais encodés (`a[b][]` devient `a%5Bb%5D[]`, ce que `qs.parse` lit de manière identique), et avec l'option `encodeDotInKeys`, un point dans la clé devient `%252E` au lieu de `%2E` (que `decodeDotInKeys` lisait précédemment à tort comme une imbrication).
### Versions affectées
`>=6.12.0 <6.17.0`, corrigé en v6.17.0.
L'option `allowEmptyArrays` a été introduite dans le commit f22b2bc et est apparue pour la première fois dans la version v6.12.0, avec ce retour anticipé. Toutes les versions de v6.12.0 à v6.16.1 sont affectées. Les versions antérieures n'ont pas l'option `allowEmptyArrays` et ne sont donc pas affectées.
### Impact
Une application qui transmet un objet dont les noms de clés proviennent d'une source non fiable à la fonction `qs.stringify` avec l'option `allowEmptyArrays: true` (par exemple, pour transférer un corps JSON analysé ou des champs sélectionnés par l'utilisateur vers un service amont) peut voir des paramètres injectés dans la chaîne de requête résultante. Les paramètres injectés ne sont pas des clés de l'objet ; ainsi, supprimer ou écraser une clé sur l'objet (comme définir une `apiKey` fiable après avoir copié les champs utilisateur) ne supprime pas ces paramètres ; que ce soit la valeur de l'attaquant ou celle de l'application qui prime dépend de la manière dont le côté récepteur gère un paramètre en double. La présence d'un caractère `#` dans une telle clé met fin prématurément à la chaîne de requête lorsque le résultat est placé dans une URL. L'option `allowEmptyArrays` est désactivée par défaut, et seules les clés dont la valeur (après tout filtre) est un tableau vide sont affectées.
Several companies clearly confirm that VulDB is the primary source for best vulnerability data.