CVE-2026-8723
Medium · 5.3CVSS
5.3
EPSS
0.4%
Published
May 17, 2026
CISA due date
—
Cloudanix analysis
A bug in a common JavaScript helper can make some applications fail requests when specially shaped empty values are sent in arrays.
- Exploitation
- Remote Unauthenticated
- Attacker needs
- None
- Complexity
- Moderate
- Impact
- Denial Of Service
- Component
- Library
- Class
- Denial of service
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
This flaw is a denial-of-service condition in the Node.js qs package affecting versions >=6.11.1 and <6.15.2. When application code calls qs.stringify with the non-default options arrayFormat: 'comma' and encodeValuesOnly: true, and the array being serialized contains null or undefined, qs attempts to encode the nullish value before null-handling logic runs. The encoder reads the value's length property without a null guard, causing a synchronous TypeError. In most HTTP frameworks, this results in the affected request returning a 500 error; in less protected contexts such as background jobs, startup code, stream pipelines, or custom handlers without an error boundary, the exception may interrupt the task or process flow.
Why it matters to the business
The main risk is application instability or degraded availability when vulnerable serialization paths process attacker-controlled or malformed data. Public APIs that accept JSON arrays and later serialize them into query strings are the most exposed. Successful exploitation typically causes request failures rather than full system compromise, but repeated triggering can create elevated error rates, disrupt integrations, degrade user experience, and increase operational load. The issue is not currently listed in CISA KEV, is not known to be used in ransomware campaigns, has low EPSS probability, and has no reported exploit maturity in the provided data, so remediation should be prioritized according to exposure of affected code paths rather than treated as an emergency internet-wide compromise risk.
How an attack unfolds
An attacker first identifies an application endpoint or workflow that accepts user-controlled structured data, especially JSON, and later passes an array from that input into qs.stringify. Exploitation requires the application to use qs.stringify with both arrayFormat: 'comma' and encodeValuesOnly: true. The attacker submits an array containing a literal null value, or otherwise influences application logic to create an array containing null or undefined. When the application attempts to serialize that array, qs enters the comma-format encode-values-only branch, maps the raw encoder over the array, and throws a TypeError while attempting to read length from the nullish element. In a typical Express, Fastify, Koa, hapi, or similar request handler with standard error handling, the attacker receives a 500 response and the process continues serving later requests. If the same vulnerable call occurs outside a protected request boundary, the synchronous exception can disrupt a background job, initialization path, pipeline, or custom process flow.
How to fix it
Upgrade the qs package to version 6.15.2 or later. The affected range is >=6.11.1 and <6.15.2; versions before 6.11.1 are not affected by this specific code path, but upgrading to the fixed current release is preferred over downgrading. Regenerate lockfiles and redeploy all applications, services, serverless functions, build tools, and background workers that bundle or depend on the vulnerable qs version. If immediate upgrade is not possible, avoid calling qs.stringify with both arrayFormat: 'comma' and encodeValuesOnly: true on arrays derived from untrusted input, or sanitize arrays before serialization by removing, replacing, or explicitly handling null and undefined elements. Ensure request handlers and background workers have robust exception handling so synchronous serialization errors cannot terminate critical processing.
How to confirm the fix worked
Confirm dependency resolution shows qs version 6.15.2 or later wherever the package is installed or bundled. For npm-based projects, use commands such as npm ls qs, npm audit, yarn why qs, pnpm why qs, or software composition analysis tooling to find direct and transitive instances. Validate that lockfiles no longer resolve qs to versions >=6.11.1 and <6.15.2. Add or run a regression test that calls qs.stringify({ a: [null, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true }) and qs.stringify({ a: [undefined, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true }); fixed versions should not throw a TypeError. In deployed environments, monitor application logs and APM traces after rollout to verify the related TypeError no longer appears and that 500-rate spikes associated with affected endpoints subside.
Typical attack path
- Find an application endpoint or workflow that accepts structured input such as JSON arrays.
- Determine or infer that the application serializes that data using qs.stringify with arrayFormat: 'comma' and encodeValuesOnly: true.
- Submit input containing an array with a null value, or trigger application logic that produces an array containing null or undefined.
- Cause the vulnerable qs.stringify call to execute on the crafted array.
- Trigger a synchronous TypeError in qs during value encoding.
- Observe a 500 response, failed job, aborted workflow, or other availability degradation.
- Repeat the request or workflow to sustain elevated error rates if the endpoint remains exposed.
How to detect it
To assess prior exploitation or triggering, search application logs, centralized logging platforms, APM error traces, serverless logs, container stdout/stderr, process manager logs, and reverse proxy metrics for synchronous TypeError events from qs followed by HTTP 500 responses or failed background jobs. Focus on time windows after the vulnerable package version was deployed and on endpoints that accept JSON arrays or perform outbound query-string construction. Useful artifacts include stack traces referencing qs lib/utils.js encode, qs lib/stringify.js, Object.maybeMap, and error messages indicating that length was read from null or undefined. Correlate matching exceptions with request bodies containing arrays with null values where request-body logging is available and policy-compliant. Also look for repeated requests from the same source that produce consistent 500 responses without corresponding application-state changes, which may indicate deliberate availability probing. Because exploitation generally causes an application error rather than code execution, indicators are primarily log and telemetry based rather than filesystem or host artifacts.
- TypeError: Cannot read properties of null (reading 'length')
- TypeError: Cannot read properties of undefined (reading 'length')
- Cannot read properties of null (reading 'length')
- Cannot read properties of undefined (reading 'length')
- at encode (lib/utils.js:195:13)
- lib/utils.js:195
- at Object.maybeMap (lib/utils.js:322:37)
- lib/utils.js:322
- at stringify (lib/stringify.js:145:25)
- lib/stringify.js:145
- arrayFormat: 'comma'
- encodeValuesOnly: true
What your security team should do
- Inventory all applications and packages that include qs, including transitive dependencies and bundled JavaScript artifacts.
- Prioritize remediation for internet-facing APIs, webhook receivers, integration gateways, and services that accept JSON arrays or construct query strings from user-controlled input.
- Upgrade qs to 6.15.2 or later and redeploy affected services; ensure lockfiles and container images are rebuilt so vulnerable copies are not retained.
- Add regression tests for qs.stringify with arrayFormat: 'comma', encodeValuesOnly: true, and arrays containing null or undefined.
- Review application code for unguarded serialization of user-controlled arrays and normalize nullish values before query-string generation where appropriate.
- Ensure web frameworks, workers, and pipeline code have error boundaries that convert synchronous exceptions into controlled failures rather than process termination.
- Create detections for the specific TypeError and stack frames associated with this bug, and investigate historical spikes in matching errors or unexplained 500 responses.
- Because EPSS is low and the issue is not KEV-listed, prioritize based on reachable vulnerable code paths rather than package presence alone.
The record
### 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`).
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| npm | qs | 6.11.1 | 6.15.2 |
Related vulnerabilities
- GHSA-q8mj-m7cp-5q26 qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/undefined… Same vulnerability
- GHSA-6rw7-vpxm-498p qs's arrayLimit bypass in its bracket notation allows DoS via memory exhaustion Also affects qs
- CVE-2025-15284 Improper Input Validation vulnerability in qs (parse modules) allows HTTP DoS.This issue… Also affects qs
- CVE-2026-112405 Pillow is a Python imaging library. CWE-476
- CVE-2026-112392 Pillow is a Python imaging library. CWE-476
- CVE-2026-100348 kin-openapi is a Go project for handling OpenAPI files. CWE-476
- CVE-2026-100349 kin-openapi is a Go project for handling OpenAPI files. CWE-476
- CVE-2026-109280 ImageMagick 7.1.0-20 before 7.1.2-32 contains a use after free vulnerability in the -fx… CWE-476