{
  "cveId": "CVE-2026-8723",
  "url": "https://patchblox.com/security/cve/CVE-2026-8723",
  "summary": "CVE-2026-8723 is fixed in node-qs on 1 platform by DEBIAN-CVE-2026-8723 (version 6.15.2\u002Bds\u002B~6.15.1-1), released May 17, 2026. It is not reported as exploited. Patch Radar priority: Routine.",
  "title": "qs.stringify crashes on null/undefined entries in comma-format arrays under encodeValuesOnly",
  "description": "### Summary    \u0060qs.stringify\u0060 throws \u0060TypeError\u0060 when called with \u0060arrayFormat: \u0027comma\u0027\u0060 and \u0060encodeValuesOnly: true\u0060 on an array containing \u0060null\u0060 or \u0060undefined\u0060. The throw is synchronous and not handled by any of qs\u0027s null-related options (\u0060skipNulls\u0060, \u0060strictNullHandling\u0060).    ### Details    In the comma \u002B \u0060encodeValuesOnly\u0060 branch, \u0060lib/stringify.js:145\u0060 mapped the array through the raw encoder before joining:    \u0060\u0060\u0060js    obj = utils.maybeMap(obj, encoder);    \u0060\u0060\u0060    \u0060utils.encode\u0060 (\u0060lib/utils.js:195\u0060) reads \u0060str.length\u0060 with no null guard, so a \u0060null\u0060 or \u0060undefined\u0060 element throws \u0060TypeError\u0060. \u0060skipNulls\u0060 and \u0060strictNullHandling\u0060 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 \u002B \u0060encodeValuesOnly\u0060 branch was introduced in 4c4b23d (\u0022encode comma values more consistently\u0022, PR #463, 2023-01-19), first released in v6.11.1.    #### PoC    \u0060\u0060\u0060js    const qs = require(\u0027qs\u0027);    qs.stringify({ a: [null, \u0027b\u0027] },      { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });    qs.stringify({ a: [undefined, \u0027b\u0027] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });    qs.stringify({ a: [null] },           { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });    // TypeError: Cannot read properties of null (reading \u0027length\u0027)    //     at encode (lib/utils.js:195:13)    //     at Object.maybeMap (lib/utils.js:322:37)    //     at stringify (lib/stringify.js:145:25)    \u0060\u0060\u0060    #### Fix    \u0060lib/stringify.js:145\u0060, applied in 21f80b3 on \u0060main\u0060 and released as v6.15.2:    \u0060\u0060\u0060diff    - obj = utils.maybeMap(obj, encoder);    \u002B obj = utils.maybeMap(obj, function (v) {    \u002B     return v == null ? v : encoder(v);    \u002B });    \u0060\u0060\u0060    \u0060null\u0060 and \u0060undefined\u0060 now pass through \u0060maybeMap\u0060 unchanged and reach the \u0060join(\u0027,\u0027)\u0060 step as-is. For \u0060{ a: [null, \u0027b\u0027] }\u0060 this produces \u0060a=,b\u0060, matching the non-\u0060encodeValuesOnly\u0060 comma path (which already joins before encoding and produces \u0060a=%2Cb\u0060 for the same input). Single-element \u0060[null]\u0060 arrays still collapse via the existing \u0060obj.join(\u0027,\u0027) || null\u0060 and remain subject to \u0060skipNulls\u0060 / \u0060strictNullHandling\u0060 in the main loop.    ### Affected versions    \u0060\u003E=6.11.1 \u003C6.15.2\u0060 \u2014 fixed in v6.15.2.    The vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions \u2014 including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 \u2014 implemented the comma \u002B \u0060encodeValuesOnly\u0060 path differently (joining before encoding) and are not affected. Empirically verified across released versions.    ### Impact    Application code that calls \u0060qs.stringify\u0060 with both \u0060arrayFormat: \u0027comma\u0027\u0060 and \u0060encodeValuesOnly: true\u0060 (both non-default) on input that may contain a \u0060null\u0060 or \u0060undefined\u0060 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\u0027s error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The \u0022kills the worker process\u0022 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 \u0060null\u0060 or \u0060undefined\u0060 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 \u0060null\u0060).",
  "published": "2026-05-17T00:16:21Z",
  "severity": "Moderate",
  "cvss": 5.3,
  "cwe": "NULL Pointer Dereference",
  "epss": 0.00399,
  "epssPercentile": 0.34445,
  "priority": "Routine",
  "priorityTier": 4,
  "exploited": false,
  "vendorExploited": false,
  "disclosed": false,
  "vendorAdvisory": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-8723",
  "fixes": [
    {
      "platform": "linux",
      "product": "node-qs",
      "release": "Debian 14",
      "fixedVersion": "6.15.2\u002Bds\u002B~6.15.1-1",
      "fix": "DEBIAN-CVE-2026-8723",
      "url": "https://patchblox.com/security/fix/linux/debian-cve-2026-8723",
      "released": "2026-05-17T00:16:21Z"
    }
  ],
  "noFixYet": [],
  "dataAsOf": "2026-11-08T06:59:42Z",
  "attribution": {
    "text": "Data: Patchblox Patch Radar",
    "url": "https://patchblox.com/security/patch-radar",
    "terms": "https://patchblox.com/security/patch-radar/use-the-data"
  }
}