CVE-2026-82417 in ljharb
Zusammenfassung
von VulDB • 30.08.2026
### Zusammenfassung
`qs.stringify` löst einen `TypeError` aus, wenn es ein Objekt serialisiert, dessen eigene `constructor`-Eigenschaft eine truthy (wahrheitswerte), nicht aufrufbare `isBuffer`-Member hat. `utils.isBuffer` duck-typet Puffer, indem es `obj.constructor.isBuffer(obj)` aufruft, nachdem nur geprüft wurde, dass die Eigenschaft truthy ist; ein Wert wie `{ constructor: { isBuffer: "x" } }` führt dazu, dass der Aufruf einen `TypeError: obj.constructor.isBuffer is not a function` auslöst.
### Details
`lib/stringify.js:127` ruft bei jedem zu serialisierenden Nicht-Primitivwert `utils.isBuffer` auf. `utils.isBuffer` (`lib/utils.js:332`) liest `obj.constructor.isBuffer` und führt es aus, ohne zu verifizieren, dass es sich um eine Funktion handelt. Da `constructor` und `isBuffer` gewöhnliche Eigenschaftsnamen sind, erreicht jedes Objekt, das diese als eigene Eigenschaften trägt, den ungeschützten Aufruf.
Ein solches Objekt kann aus nicht vertrauenswürdigen Eingaben erstellt werden. `qs.parse("x[constructor][isBuffer]=y", { plainObjects: true })` oder `{ allowPrototypes: true }` behält den Schlüssel `constructor` als eigene Eigenschaft bei (die Standard-Parse-Optionen entfernen ihn), und `JSON.parse("{\"a\":{\"constructor\":{\"isBuffer\":\"x\"}}}")` erzeugt dieselbe Struktur ohne Beteiligung von qs-Optionen. Express 4 mit seiner Standardeinstellung für den `query parser` sowie body-parser mit `extended: true` rufen beide `qs.parse` mit `allowPrototypes: true` auf, sodass in diesen Stacks `req.query` und `req.body` die Struktur direkt enthalten können.
#### PoC (Proof of Concept)
```js var qs = require("qs");
qs.stringify(qs.parse("x[constructor][isBuffer]=y", { plainObjects: true }));
qs.stringify(JSON.parse("{\"a\":{\"constructor\":{\"isBuffer\":\"x\"}}}"));
// TypeError: obj.constructor.isBuffer is not a function // at Object.isBuffer (lib/utils.js:332:78) // at stringify (lib/stringify.js:127:45) ```
#### Fix
`lib/utils.js`, angewendet in e83d321 auf `main` und veröffentlicht als v6.16.0:
```diff - return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); + return !!(obj.constructor && typeof obj.constructor.isBuffer === "function" && obj.constructor.isBuffer(obj)); ```
Echte `Buffer`-, `safer-buffer`- und browserify `buffer` Polyfill-Instanzen werden genau wie zuvor serialisiert; nur der Auslöser des Fehlers wird entfernt.
### Betroffene Versionen
`>=2.2.5 <6.16.0`, behoben in v6.16.0.
Der ungeschützte Duck-Type wurde in 3768a75 eingeführt und erstmals in v2.2.5 (September 2014) ausgeliefert. v2.2.4 und frühere Versionen verwendeten `Buffer.isBuffer` und sind nicht betroffen. Jede Veröffentlichung von v2.2.5 bis v6.15.3 enthält den ungeschützten Aufruf.
### Auswirkung
Eine unberechtigte Anfrage kann dazu führen, dass jeder Codepfad, der angreifergesteuerte Daten mit `qs.stringify` neu serialisiert (z. B. das Neuerstellen einer Query-String aus `req.query` für eine Weiterleitung oder eine Upstream-Anfrage sowie die Serialisierung eines analysierten JSON-Corpus), synchron einen Fehler auslöst. In einem typischen Node.js HTTP-Framework wird der Fehler durch den Framework-Fehlergrenzwert (error boundary) abgefangen, und die betroffene Anfrage gibt einen 500-Statuscode zurück; der Prozess überlebt, und andere Anfragen sind nicht betroffen. Wenn der Aufruf außerhalb einer Fehlergrenze ausgeführt wird, wie z. B. in einem `async` Express 4 Handler (wo der Auslöser zu einer unbehandelten Promise-Ablehnung wird) oder in einem Hintergrundjob, endet der Prozess; die Auswirkung hängt in diesem Fall von der Anwendungsfehlerbehandlung ab und nicht von qs.
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.