Instituto Nacional de ciberseguridad. Sección Incibe
Instituto Nacional de Ciberseguridad. Sección INCIBE-CERT

CVE-2026-82417

Gravedad CVSS v4.0:
MEDIA
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
30/08/2026
Última modificación:
30/08/2026

Descripción

*** Pendiente de traducción *** ### Summary<br /> <br /> <br /> <br /> `qs.stringify` throws a `TypeError` when it serializes an object whose own `constructor` property has a truthy, non-callable `isBuffer` member. `utils.isBuffer` duck-types buffers by calling `obj.constructor.isBuffer(obj)` after checking only that the property is truthy, so a value such as `{ constructor: { isBuffer: "x" } }` makes the call throw `TypeError: obj.constructor.isBuffer is not a function`.<br /> <br /> <br /> <br /> ### Details<br /> <br /> <br /> <br /> `lib/stringify.js:127` calls `utils.isBuffer` on every non-primitive value it serializes. `utils.isBuffer` (`lib/utils.js:332`) reads `obj.constructor.isBuffer` and invokes it without verifying that it is a function. `constructor` and `isBuffer` are ordinary property names, so any object carrying them as own properties reaches the unchecked call.<br /> <br /> <br /> <br /> Such an object can be built from untrusted input. `qs.parse("x[constructor][isBuffer]=y", { plainObjects: true })` or `{ allowPrototypes: true }` keeps the `constructor` key as an own property (the default parse options drop it), and `JSON.parse("{\"a\":{\"constructor\":{\"isBuffer\":\"x\"}}}")` produces the same shape with no qs option involved. Express 4 with its default `query parser` setting and body-parser with `extended: true` both call `qs.parse` with `allowPrototypes: true`, so on those stacks `req.query` and `req.body` can carry the shape directly.<br /> <br /> <br /> <br /> #### PoC<br /> <br /> <br /> <br /> ```js<br /> <br /> <br /> <br /> var qs = require("qs");<br /> <br /> <br /> <br /> qs.stringify(qs.parse("x[constructor][isBuffer]=y", { plainObjects: true }));<br /> <br /> <br /> <br /> qs.stringify(JSON.parse("{\"a\":{\"constructor\":{\"isBuffer\":\"x\"}}}"));<br /> <br /> <br /> <br /> // TypeError: obj.constructor.isBuffer is not a function<br /> <br /> <br /> <br /> // at Object.isBuffer (lib/utils.js:332:78)<br /> <br /> <br /> <br /> // at stringify (lib/stringify.js:127:45)<br /> <br /> <br /> <br /> ```<br /> <br /> <br /> <br /> #### Fix<br /> <br /> <br /> <br /> `lib/utils.js`, applied in e83d321 on `main` and released as v6.16.0:<br /> <br /> <br /> <br /> ```diff<br /> <br /> <br /> <br /> - return !!(obj.constructor &amp;&amp; obj.constructor.isBuffer &amp;&amp; obj.constructor.isBuffer(obj));<br /> <br /> <br /> <br /> + return !!(obj.constructor &amp;&amp; typeof obj.constructor.isBuffer === "function" &amp;&amp; obj.constructor.isBuffer(obj));<br /> <br /> <br /> <br /> ```<br /> <br /> <br /> <br /> Real `Buffer`, `safer-buffer`, and browserify `buffer` polyfill instances serialize exactly as before; only the throw is removed.<br /> <br /> <br /> <br /> ### Affected versions<br /> <br /> <br /> <br /> `&gt;=2.2.5