CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-8723
5.30.04%

CVE-2026-8723: Synchronous Denial of Service in qs npm Package via TypeError

Amit Schendel
Amit Schendel
Senior Security Researcher

May 22, 2026·7 min read·15 visits

PoC Available

Executive Summary (TL;DR)

A configuration-dependent vulnerability in qs.stringify allows attackers to crash the hosting Node.js process by supplying arrays with null or undefined elements when comma formatting and encodeValuesOnly are enabled.

The qs query string parsing and serialization library for Node.js is vulnerable to a synchronous Denial of Service (DoS) attack. The vulnerability manifests as a process-terminating TypeError when processing arrays with null or undefined elements under specific configuration parameters.

Vulnerability Overview

The qs package is a fundamental utility in the Node.js ecosystem used for parsing and stringifying URL query strings. It provides extensive configuration options for handling complex data structures, including nested objects and arrays. Applications frequently use this library to serialize data before constructing HTTP requests or to parse incoming request parameters. The vulnerability resides in the serialization logic of the qs.stringify function, specifically within the array formatting module.

This flaw is classified under CWE-476 (NULL Pointer Dereference) as it involves an unsafe property access on a null or undefined object type in JavaScript. The condition is triggered exclusively when two specific options are provided to qs.stringify: arrayFormat: 'comma' and encodeValuesOnly: true. When these options are active, the library attempts to process array elements before standard null-handling checks are evaluated.

The immediate consequence of this vulnerability is a synchronous TypeError. In a standard Node.js environment, unhandled synchronous exceptions terminate the worker process immediately. If an application routes attacker-controlled data into qs.stringify using the affected configuration without a surrounding try-catch block, remote attackers can achieve a persistent Denial of Service (DoS) state by continuously sending malformed inputs.

Root Cause Analysis

The vulnerability stems from an architectural flaw in how the qs library sequences array formatting operations and data encoding. In lib/stringify.js, when the arrayFormat: 'comma' option is specified, the execution flow enters a dedicated branch designed to collapse the array into a single comma-separated string early in the processing loop. This early evaluation path bypasses the standard null-validation mechanisms that occur later in the object traversal logic.

Within this branch, if the encodeValuesOnly option is active, the code executes obj = utils.maybeMap(obj, encoder);. This operation applies the selected encoding function to every element in the array prior to the string joining operation. The default encoder utilized by the library, located at lib/utils.js:195, expects a string-like object as its input parameter. It immediately attempts to access the .length property of the provided value to determine encoding requirements.

When an array contains a null or undefined element, the utils.maybeMap function passes these specific types directly to the default encoder. The JavaScript runtime cannot access properties on null or undefined, causing the encoder to throw a TypeError: Cannot read properties of null (reading 'length'). Because this mapping operation occurs before the main execution loop evaluates options like skipNulls and strictNullHandling, those protective configurations are rendered entirely ineffective against this crash.

Code Analysis

A detailed review of the vulnerable code path demonstrates the unsafe delegation to the encoder function. In versions >=6.11.1 <6.15.2, the implementation in lib/stringify.js at line 145 passes array elements directly to the encoder without verifying their type. This blind delegation assumes that all array elements are primitives that possess a .length property or can be safely coerced by the encoder.

The vulnerable snippet executes the following logic:

if (generateArrayPrefix === 'comma' && isArray(obj)) {
    if (encodeValuesOnly && encoder) {
        obj = utils.maybeMap(obj, encoder);
    }
    objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
}

The patch introduced in commit 21f80b33e5c8b3f7eba1034fff0da4a4a37a1d41 remediates this by introducing an inline validation wrapper around the encoder function. The modification ensures that null or undefined values are returned verbatim, preventing them from reaching the vulnerable property access within the encoder.

--- a/lib/stringify.js
+++ b/lib/stringify.js
@@ -142,7 +142,9 @@ var stringify = function stringify(
     if (generateArrayPrefix === 'comma' && isArray(obj)) {
         // we need to join elements in
         if (encodeValuesOnly && encoder) {
-            obj = utils.maybeMap(obj, encoder);
+            obj = utils.maybeMap(obj, function (v) {
+                return v == null ? v : encoder(v);
+            });
         }
         objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];

This fix successfully averts the exception by utilizing the loose equality operator (v == null), which correctly identifies both null and undefined primitives. These values bypass the encoder and proceed to the .join(',') operation, which standard JavaScript arrays inherently handle by coercing them to empty strings.

Exploitation and Attack Methodology

Exploiting CVE-2026-8723 requires the attacker to identify an application endpoint that invokes qs.stringify using the exact combination of arrayFormat: 'comma' and encodeValuesOnly: true. Furthermore, the attacker must have a mechanism to supply an array containing at least one null or undefined element into the data structure processed by this function. This data injection typically occurs via JSON request bodies or URL-encoded payloads that the server reconstructs into JavaScript objects.

Once the preconditions are met, exploitation is trivial. The attacker submits the malformed payload, triggering the execution path described in the root cause analysis. Node.js processes the request synchronously until it encounters the qs.stringify call. The subsequent TypeError bubbles up the call stack immediately. If the server implementation does not wrap the vulnerable function call in a try-catch block, the exception reaches the Node.js event loop top-level handler, resulting in process termination.

The following proof-of-concept demonstrates the fundamental crash mechanics. When executed, each of these statements terminates the script execution entirely unless caught by an error handler.

const qs = require('qs');
 
// Demonstrating the crash with null values
try {
    qs.stringify({ a: [null, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });
} catch (e) {
    console.error('Crash verified:', e.message);
}
 
// Demonstrating the crash with undefined values
try {
    qs.stringify({ a: [undefined, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });
} catch (e) {
    console.error('Crash verified:', e.message);
}

Impact Assessment

The primary security impact of this vulnerability is a localized Denial of Service (DoS). The CVSS v3.1 vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L accurately reflects this, highlighting that the vulnerability is network-exploitable, requires no specific privileges or user interaction, and possesses low attack complexity. The availability impact is rated as 'Low' because the crash typically affects a single worker process rather than completely halting a distributed system or cluster.

However, in environments running single-threaded Node.js applications without process managers (such as PM2) or orchestration-level health checks (such as Kubernetes readiness probes), a single payload can render the service permanently unavailable. Even in resilient environments, continuous exploitation forces constant application restarts. This degrades overall service performance, drops active connections, and heavily consumes server resources during process initialization.

The exploit maturity is currently documented as Proof of Concept (PoC). The provided EPSS score of 0.00044 (13.63 percentile) indicates a very low observed probability of exploitation in the wild. Despite this low statistical risk, the deterministic nature of the crash and the widespread usage of the qs library necessitate prompt remediation.

Remediation and Mitigation Guidance

The definitive resolution for CVE-2026-8723 is to upgrade the qs library to version 6.15.2 or later. This version contains the patch that correctly sanitizes array elements before passing them to the encoder function. Package managers will typically resolve this issue automatically by running npm update qs or adjusting the package.json constraints to exclude the vulnerable version range >=6.11.1 <6.15.2.

If upgrading the library is not immediately feasible due to legacy dependencies, developers must implement temporary mitigations. The most straightforward approach is to modify the qs.stringify options object to remove either arrayFormat: 'comma' or encodeValuesOnly: true. Disabling either of these specific options prevents the execution flow from entering the vulnerable branch within lib/stringify.js.

Additionally, applications can implement defensive programming practices around data serialization. Wrapping all calls to qs.stringify within a try-catch block ensures that any unexpected type errors are caught and handled gracefully, preventing process termination. Implementing strict input validation to sanitize data objects and remove literal null or undefined values before serialization provides a secondary layer of defense.

Official Patches

ljharbCommit fixing the null property access issue

Fix Analysis (1)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
EPSS Probability
0.04%
Top 86% most exploited

Affected Systems

Node.js applicationsProjects utilizing the qs npm package versions 6.11.1 through 6.15.1

Affected Versions Detail

Product
Affected Versions
Fixed Version
qs
ljharb
>= 6.11.1 < 6.15.26.15.2
AttributeDetail
CWE IDCWE-476
Attack VectorNetwork
CVSS v3.15.3
EPSS Score0.00044
ImpactDenial of Service (Process Termination)
Exploit Statuspoc
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-476
NULL Pointer Dereference

NULL Pointer Dereference

Known Exploits & Detection

Vendor AdvisoryPublic proof of concept exploiting the qs.stringify TypeError crash

Vulnerability Timeline

Vulnerability introduced in version 6.11.1 (commit 4c4b23d)
2023-01-19
Vulnerability fixed in version 6.15.2
2026-05-16
GitHub Advisory published (GHSA-q8mj-m7cp-5q26)
2026-05-16
CVE assigned and published to NVD
2026-05-17

References & Sources

  • [1]GitHub Advisory: GHSA-q8mj-m7cp-5q26
  • [2]NVD Record for CVE-2026-8723
  • [3]CVE.org Record for CVE-2026-8723

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.