6.3
MEDIUM CVSS 4.0
CVE-2026-82417
qs.stringify throws TypeError on objects with a non-callable constructor.isBuffer property
Description

### Summary `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`. ### Details `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. 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. #### PoC ```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`, applied in e83d321 on `main` and released as 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)); ``` Real `Buffer`, `safer-buffer`, and browserify `buffer` polyfill instances serialize exactly as before; only the throw is removed. ### Affected versions `>=2.2.5 <6.16.0`, fixed in v6.16.0. The unguarded duck-type was introduced in 3768a75 and first shipped in v2.2.5 (September 2014). v2.2.4 and earlier used `Buffer.isBuffer` and are not affected. Every release from v2.2.5 through v6.15.3 contains the unguarded call. ### Impact An unauthenticated request can make any code path that re-serializes attacker-influenced data with `qs.stringify` (for example, rebuilding a query string from `req.query` for a redirect or an upstream request, or serializing a parsed JSON body) throw synchronously. In a typical Node.js HTTP framework the throw is caught by the framework error boundary and the affected request returns a 500; the process survives and other requests are unaffected. Where the call runs outside an error boundary, such as an `async` Express 4 handler (where the throw becomes an unhandled promise rejection) or a background job, the process exits, so the impact in that case depends on the application error handling rather than on qs.

INFO

Published Date :

Aug. 30, 2026, 12:16 a.m.

Last Modified :

Aug. 30, 2026, 12:16 a.m.

Remotely Exploit :

Yes !

Source :

7ffcee3d-2c14-4c3e-b844-86c6a321a158
Affected Products

The following products are affected by CVE-2026-82417 vulnerability. Even if cvefeed.io is aware of the exact versions of the products that are affected, the information is not represented in the table below.

No affected product recoded yet

CVSS Scores
The Common Vulnerability Scoring System is a standardized framework for assessing the severity of vulnerabilities in software and systems. We collect and displays CVSS scores from various sources for each CVE.
Score Version Severity Vector Exploitability Score Impact Score Source
CVSS 3.1 MEDIUM 7ffcee3d-2c14-4c3e-b844-86c6a321a158
CVSS 4.0 MEDIUM 7ffcee3d-2c14-4c3e-b844-86c6a321a158
CVSS 4.0 MEDIUM 7ffcee3d-2c14-4c3e-b844-86c6a321a158
Solution
Update the qs library to version 6.16.0 or later to fix a TypeError.
  • Update the qs library to the latest version.
  • Ensure the constructor property is not used in this manner.
  • Avoid re-serializing untrusted data with qs.stringify.
References to Advisories, Solutions, and Tools

Here, you will find a curated list of external links that provide in-depth information, practical solutions, and valuable tools related to CVE-2026-82417.

URL Resource
https://github.com/ljharb/qs/commit/e83d321ffafb38cf210683ac31714fce6ce1c6c6
https://github.com/ljharb/qs/security/advisories/GHSA-4mjr-xmp4-gh2g
CWE - Common Weakness Enumeration

While CVE identifies specific instances of vulnerabilities, CWE categorizes the common flaws or weaknesses that can lead to vulnerabilities. CVE-2026-82417 is associated with the following CWEs:

Common Attack Pattern Enumeration and Classification (CAPEC)

Common Attack Pattern Enumeration and Classification (CAPEC) stores attack patterns, which are descriptions of the common attributes and approaches employed by adversaries to exploit the CVE-2026-82417 weaknesses.

We scan GitHub repositories to detect new proof-of-concept exploits. Following list is a collection of public exploits and proof-of-concepts, which have been published on GitHub (sorted by the most recently updated).

Results are limited to the first 15 repositories due to potential performance issues.

The following list is the news that have been mention CVE-2026-82417 vulnerability anywhere in the article.

The following table lists the changes that have been made to the CVE-2026-82417 vulnerability over time.

Vulnerability history details can be useful for understanding the evolution of a vulnerability, and for identifying the most recent changes that may impact the vulnerability's severity, exploitability, or other characteristics.

  • New CVE Received by 7ffcee3d-2c14-4c3e-b844-86c6a321a158

    Aug. 30, 2026

    Action Type Old Value New Value
    Added Description ### Summary `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`. ### Details `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. 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. #### PoC ```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`, applied in e83d321 on `main` and released as 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)); ``` Real `Buffer`, `safer-buffer`, and browserify `buffer` polyfill instances serialize exactly as before; only the throw is removed. ### Affected versions `>=2.2.5 <6.16.0`, fixed in v6.16.0. The unguarded duck-type was introduced in 3768a75 and first shipped in v2.2.5 (September 2014). v2.2.4 and earlier used `Buffer.isBuffer` and are not affected. Every release from v2.2.5 through v6.15.3 contains the unguarded call. ### Impact An unauthenticated request can make any code path that re-serializes attacker-influenced data with `qs.stringify` (for example, rebuilding a query string from `req.query` for a redirect or an upstream request, or serializing a parsed JSON body) throw synchronously. In a typical Node.js HTTP framework the throw is caught by the framework error boundary and the affected request returns a 500; the process survives and other requests are unaffected. Where the call runs outside an error boundary, such as an `async` Express 4 handler (where the throw becomes an unhandled promise rejection) or a background job, the process exits, so the impact in that case depends on the application error handling rather than on qs.
    Added CVSS V4.0 AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
    Added CVSS V3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
    Added CWE CWE-248
    Added CWE CWE-703
    Added Affected New affected value received. <a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/82xxx/CVE-2026-82417.json">CVE-2026-82417</a>
    Added Reference https://github.com/ljharb/qs/commit/e83d321ffafb38cf210683ac31714fce6ce1c6c6
    Added Reference https://github.com/ljharb/qs/security/advisories/GHSA-4mjr-xmp4-gh2g
EPSS is a daily estimate of the probability of exploitation activity being observed over the next 30 days. Following chart shows the EPSS score history of the vulnerability.