CVE-2026-82417
Received Received - Intake

TypeError in qs.stringify due to unguarded constructor.isBuffer call

Vulnerability report for CVE-2026-82417, including description, CVSS score, EPSS score, affected products, exploitability, helpful resources, and attack-flow context.

Publication date: 2026-08-30

Last updated on: 2026-08-30

Assigner: harborist

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.

CVSS Scores

EPSS Scores

Probability:
Percentile:

Meta Information

Published
2026-08-30
Last Modified
2026-08-30
Generated
2026-08-30
AI Q&A
2026-08-30
EPSS Evaluated
N/A
NVD

Affected Vendors & Products

Showing 3 associated CPEs
Vendor Product Version / Range
ljharb qs 2.2.5
ljharb qs 6.15.3
ljharb qs From 2.2.5 (inc) to 6.16.0 (exc)

Helpful Resources

Exploitability

CWE
CWE Icon
KEV
KEV Icon
CWE ID Description
CWE-248 An exception is thrown from a function, but it is not caught.
CWE-703 The product does not properly anticipate or handle exceptional conditions that rarely occur during normal operation of the product.

Attack-Flow Graph

AI Quick Actions

Instant insights powered by AI
Executive Summary

This vulnerability in the qs library occurs when qs.stringify() calls utils.isBuffer() on serialized values. The function invokes obj.constructor.isBuffer(obj) without checking if isBuffer is a callable function. Attackers can craft objects with a non-function isBuffer property, causing a TypeError when qs.stringify() processes them. This leads to application crashes or denial of service.

Detection Guidance

Check if your system uses the affected qs library versions (2.2.5 to 6.15.3). Run: npm list qs or grep -r 'qs' node_modules. If vulnerable, update to v6.16.0 or later.

Impact Analysis

An attacker can send a malicious request that triggers a TypeError when qs.stringify() processes untrusted data. This causes the application to crash, returning a 500 error in typical frameworks. In async contexts or background jobs, the process may exit entirely, leading to denial of service. The impact depends on the application's error handling and framework configuration.

Compliance Impact

This vulnerability primarily causes denial of service by crashing applications through uncaught exceptions, which could lead to service unavailability. For GDPR, this may impact availability of personal data processing systems. For HIPAA, it could disrupt healthcare services relying on the qs library for data handling.

Mitigation Strategies

Upgrade the qs library to version 6.16.0 or higher immediately. For applications using Express 4 or body-parser, ensure query parsing does not use allowPrototypes: true or plainObjects: true options.

Chat Assistant

Ask questions about this CVE
Hi! I’m here to help you understand CVE-2026-82417. Ask me anything about the vulnerability, its impact, or mitigation strategies.
0/70

EPSS Chart