Description
### Summary



`qs.stringify` throws `TypeError` when called with `arrayFormat: 'comma'` and `encodeValuesOnly: true` on an array containing `null` or `undefined`. The throw is synchronous and not handled by any of qs's null-related options (`skipNulls`, `strictNullHandling`).



### Details



In the comma + `encodeValuesOnly` branch, `lib/stringify.js:145` mapped the array through the raw encoder before joining:



```js



obj = utils.maybeMap(obj, encoder);



```



`utils.encode` (`lib/utils.js:195`) reads `str.length` with no null guard, so a `null` or `undefined` element throws `TypeError`. `skipNulls` and `strictNullHandling` are both checked in the per-element loop below this line and never get a chance to run.



Same class of bug as the filter-array path fixed in 0c180a4. The vulnerable shape of the comma + `encodeValuesOnly` branch was introduced in 4c4b23d ("encode comma values more consistently", PR #463, 2023-01-19), first released in v6.11.1.



#### PoC



```js



const qs = require('qs');



qs.stringify({ a: [null, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });



qs.stringify({ a: [undefined, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });



qs.stringify({ a: [null] }, { arrayFormat: 'comma', encodeValuesOnly: true });



// TypeError: Cannot read properties of null (reading 'length')



// at encode (lib/utils.js:195:13)



// at Object.maybeMap (lib/utils.js:322:37)



// at stringify (lib/stringify.js:145:25)



```



#### Fix



`lib/stringify.js:145`, applied in 21f80b3 on `main` and released as v6.15.2:



```diff



- obj = utils.maybeMap(obj, encoder);



+ obj = utils.maybeMap(obj, function (v) {



+ return v == null ? v : encoder(v);



+ });



```



`null` and `undefined` now pass through `maybeMap` unchanged and reach the `join(',')` step as-is. For `{ a: [null, 'b'] }` this produces `a=,b`, matching the non-`encodeValuesOnly` comma path (which already joins before encoding and produces `a=%2Cb` for the same input). Single-element `[null]` arrays still collapse via the existing `obj.join(',') || null` and remain subject to `skipNulls` / `strictNullHandling` in the main loop.



### Affected versions



`>=6.11.1 <6.15.2` — fixed in v6.15.2.



The vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions — including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 — implemented the comma + `encodeValuesOnly` path differently (joining before encoding) and are not affected. Empirically verified across released versions.



### Impact



Application code that calls `qs.stringify` with both `arrayFormat: 'comma'` and `encodeValuesOnly: true` (both non-default) on input that may contain a `null` or `undefined` array element will throw synchronously instead of producing a query string. In a typical Node.js HTTP framework (Express, Fastify, Koa, hapi) the sync throw is caught by the framework's error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The "kills the worker process" framing applies only to call sites outside a request-handler error boundary (background jobs, startup paths, stream pipelines) or to deployments with framework error handling explicitly disabled.



The vulnerable input is a `null` or `undefined` entry inside an array; this is reachable from JSON request bodies or from application code constructing arrays from user input, but not from standard HTML form submissions (which produce strings or omitted fields, not literal `null`).
Published: 2026-05-16
Score: 6.3 Medium
EPSS: n/a
KEV: No
Impact: n/a
Action: n/a
AI Analysis

Impact

A synchronous TypeError occurs when the qs library processes a comma‑formatted array with the encodeValuesOnly flag set to true if any element is null or undefined. The error arises in lib/utils.js while reading the length property of a nullish value. The exception propagates out of qs.stringify and is typically trapped by an HTTP framework’s error boundary, causing the current request to fail with a 500 status code. In environments where the error is not caught—such as background jobs or startup scripts—the worker process may terminate, resulting in a brief denial of service for all subsequent requests. This vulnerability does not provide code execution or information disclosure but can degrade availability for applications that rely on qs.stringify for query string construction.

Affected Systems

The flaw exists in versions of the ljharb:qs package from 6.11.1 up to, but not including, 6.15.2. Earlier releases (6.7.x through 6.11.0) handled the comma+encodeValuesOnly case differently and are not affected. The issue surfaces only when callers supply both arrayFormat:'comma' and encodeValuesOnly:true to qs.stringify with inputs that may contain null or undefined elements.

Risk and Exploitability

The CVSS score of 6.3 classifies this as moderate severity. No EPSS data is available; it is not listed in the CISA KEV catalog. Exploitation requires no special privileges; any user able to influence the data passed to qs.stringify can trigger the fault. In typical web applications the impact manifests as service interruptions or increased error rate, but the technical barrier is low and the crash is immediate once the vulnerable combination is invoked.

Generated by OpenCVE AI on May 17, 2026 at 00:50 UTC.

Remediation

No vendor fix or workaround currently provided.

OpenCVE Recommended Actions

  • Upgrade the qs package to version 6.15.2 or later, which contains a guard that passes null and undefined values through the encoder without attempting to read their length.
  • Refactor any code that calls qs.stringify with arrayFormat:'comma' and encodeValuesOnly:true to avoid passing null or undefined elements, or remove one of the flags when suitable.
  • As a temporary workaround, avoid the encodeValuesOnly flag for comma‑formatted arrays by setting skipNulls:true or handling null values explicitly before calling stringify.

Generated by OpenCVE AI on May 17, 2026 at 00:50 UTC.

Tracking

Sign in to view the affected projects.

Advisories

No advisories yet.

History

Sun, 17 May 2026 00:45:00 +0000

Type Values Removed Values Added
First Time appeared Ljharb
Ljharb qs
Vendors & Products Ljharb
Ljharb qs

Sat, 16 May 2026 23:45:00 +0000

Type Values Removed Values Added
Description ### Summary `qs.stringify` throws `TypeError` when called with `arrayFormat: 'comma'` and `encodeValuesOnly: true` on an array containing `null` or `undefined`. The throw is synchronous and not handled by any of qs's null-related options (`skipNulls`, `strictNullHandling`). ### Details In the comma + `encodeValuesOnly` branch, `lib/stringify.js:145` mapped the array through the raw encoder before joining: ```js obj = utils.maybeMap(obj, encoder); ``` `utils.encode` (`lib/utils.js:195`) reads `str.length` with no null guard, so a `null` or `undefined` element throws `TypeError`. `skipNulls` and `strictNullHandling` are both checked in the per-element loop below this line and never get a chance to run. Same class of bug as the filter-array path fixed in 0c180a4. The vulnerable shape of the comma + `encodeValuesOnly` branch was introduced in 4c4b23d ("encode comma values more consistently", PR #463, 2023-01-19), first released in v6.11.1. #### PoC ```js const qs = require('qs'); qs.stringify({ a: [null, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true }); qs.stringify({ a: [undefined, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true }); qs.stringify({ a: [null] }, { arrayFormat: 'comma', encodeValuesOnly: true }); // TypeError: Cannot read properties of null (reading 'length') // at encode (lib/utils.js:195:13) // at Object.maybeMap (lib/utils.js:322:37) // at stringify (lib/stringify.js:145:25) ``` #### Fix `lib/stringify.js:145`, applied in 21f80b3 on `main` and released as v6.15.2: ```diff - obj = utils.maybeMap(obj, encoder); + obj = utils.maybeMap(obj, function (v) { + return v == null ? v : encoder(v); + }); ``` `null` and `undefined` now pass through `maybeMap` unchanged and reach the `join(',')` step as-is. For `{ a: [null, 'b'] }` this produces `a=,b`, matching the non-`encodeValuesOnly` comma path (which already joins before encoding and produces `a=%2Cb` for the same input). Single-element `[null]` arrays still collapse via the existing `obj.join(',') || null` and remain subject to `skipNulls` / `strictNullHandling` in the main loop. ### Affected versions `>=6.11.1 <6.15.2` — fixed in v6.15.2. The vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions — including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 — implemented the comma + `encodeValuesOnly` path differently (joining before encoding) and are not affected. Empirically verified across released versions. ### Impact Application code that calls `qs.stringify` with both `arrayFormat: 'comma'` and `encodeValuesOnly: true` (both non-default) on input that may contain a `null` or `undefined` array element will throw synchronously instead of producing a query string. In a typical Node.js HTTP framework (Express, Fastify, Koa, hapi) the sync throw is caught by the framework's error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The "kills the worker process" framing applies only to call sites outside a request-handler error boundary (background jobs, startup paths, stream pipelines) or to deployments with framework error handling explicitly disabled. The vulnerable input is a `null` or `undefined` entry inside an array; this is reachable from JSON request bodies or from application code constructing arrays from user input, but not from standard HTML form submissions (which produce strings or omitted fields, not literal `null`).
Title qs.stringify crashes on null/undefined entries in comma-format arrays under encodeValuesOnly
Weaknesses CWE-476
References
Metrics cvssV3_1

{'score': 5.3, 'vector': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L'}

cvssV4_0

{'score': 6.3, 'vector': 'CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N'}


cve-icon MITRE

Status: PUBLISHED

Assigner: harborist

Published:

Updated: 2026-05-16T23:21:16.035Z

Reserved: 2026-05-16T06:26:43.607Z

Link: CVE-2026-8723

cve-icon Vulnrichment

No data.

cve-icon NVD

Status : Received

Published: 2026-05-17T00:16:21.233

Modified: 2026-05-17T00:16:21.233

Link: CVE-2026-8723

cve-icon Redhat

No data.

cve-icon OpenCVE Enrichment

Updated: 2026-05-17T01:00:11Z

Weaknesses