{"id":"EUVD-2026-101710","enisaUuid":"67f1ce93-b9b5-3152-964e-c086a6ab961f","description":"qs : qs.stringify with arrayFormat \u0027comma\u0027 throws an uncaught TypeError on array elements carrying a non-callable own toString (DoS)","datePublished":"Oct 27, 2026, 4:10:55 PM","dateUpdated":"Oct 27, 2026, 4:10:55 PM","baseScore":6.3,"baseScoreVersion":"4.0","baseScoreVector":"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","references":"https://github.com/ljharb/qs/security/advisories/GHSA-6pq8-jhm2-2vcw\nhttps://github.com/ljharb/qs/commit/a952e7519338ef0cfb25694a2988848f93333727\nhttps://nvd.nist.gov/vuln/detail/CVE-2026-110816\nhttps://github.com/ljharb/qs/releases/tag/v6.16.1\n","aliases":"CVE-2026-110816\nGHSA-6pq8-jhm2-2vcw\n","assigner":"harborist","epss":0.37,"enisaIdProduct":[{"id":"35fe0adb-56af-3f40-ab43-8855cd702068","product":{"name":"qs","vendor":{"name":"ljharb"}},"product_version":"6.7.0 \u003c6.16.1"}],"enisaIdVendor":[{"id":"a6c6780d-af13-38b6-88cc-638ae6c21c37","vendor":{"name":"ljharb"}}],"enisaIdVulnerability":[{"id":"b21b2e5a-7c76-378d-bcb1-20de842cb2df","vulnerability":{"id":"GHSA-6pq8-jhm2-2vcw","description":"qs : qs.stringify with arrayFormat \u0027comma\u0027 throws an uncaught TypeError on array elements carrying a non-callable own toString (DoS)","datePublished":"Oct 27, 2026, 4:10:55 PM","dateUpdated":"Oct 27, 2026, 4:10:55 PM","baseScore":0.0,"references":"https://github.com/ljharb/qs/security/advisories/GHSA-6pq8-jhm2-2vcw\nhttps://nvd.nist.gov/vuln/detail/CVE-2026-110816\nhttps://github.com/ljharb/qs/commit/a952e7519338ef0cfb25694a2988848f93333727\nhttps://github.com/ljharb/qs\nhttps://github.com/ljharb/qs/releases/tag/v6.16.1\n","enisa_id":"EUVD-2026-101710\n","aliases":"CVE-2026-110816\nGHSA-6pq8-jhm2-2vcw\n","epss":0.0,"dataProcessed":"Oct 28, 2026, 2:02:34 AM","vulnerabilityProduct":[],"vulnerabilityVendor":[]}},{"id":"bcdced32-d297-3edc-9859-b0a6393cc29a","vulnerability":{"id":"CVE-2026-110816","description":"### Summary\n\n\n\n`qs.stringify` with `arrayFormat: \u0027comma\u0027` throws `TypeError: Cannot convert object to primitive value` when an array element cannot be coerced to a string, such as an object with an own non-callable `toString` (`{ \"toString\": \"x\" }`) or a null-prototype object. The comma format joins array elements with `Array.prototype.join` and, under `encodeValuesOnly`, first passes each element through `String()` in `utils.encode`; neither guards against an element whose string coercion fails.\n\n\n\n### Details\n\n\n\nIn `lib/stringify.js`, the comma branch collapses the array with `obj.join(\u0027,\u0027)`. For an element whose own `toString` is not callable, `ToPrimitive` skips it, falls through to `Object.prototype.valueOf` (which returns the object itself), and throws. Under `encodeValuesOnly: true`, the same element first reaches `String(str)` in `utils.encode` (`lib/utils.js`) and throws there. Nested arrays (`{ \"a\": [[{ \"toString\": \"x\" }]] }`) throw the same way, through `Array.prototype.toString`. The `indices`, `brackets`, and `repeat` formats walk into object elements instead of coercing them, and are not affected.\n\n\n\nSuch elements can come from untrusted input. `JSON.parse` produces `{ \"a\": [{ \"toString\": \"x\" }] }` with no qs option involved. `qs.parse(\"a[0][toString]\u003dx\", { allowPrototypes: true })` keeps the `toString` key, and `qs.parse(\"a[][b]\u003dc\", { plainObjects: true })` produces a null-prototype element; the default parse options drop `toString` and produce ordinary objects, which do not throw. Express 4\u0027s default `query parser`, Express 5\u0027s `extended` query parser, and body-parser\u0027s `urlencoded({ extended: true })` all call `qs.parse` with `allowPrototypes: true`.\n\n\n\n#### PoC\n\n\n\n```js\n\n\n\nvar qs \u003d require(\"qs\");\n\n\n\nqs.stringify(JSON.parse(\"{\\\"a\\\":[{\\\"toString\\\":\\\"x\\\"}]}\"), { arrayFormat: \"comma\" });\n\n\n\nqs.stringify(qs.parse(\"a[0][toString]\u003dx\", { allowPrototypes: true }), { arrayFormat: \"comma\" });\n\n\n\nqs.stringify(qs.parse(\"a[][b]\u003dc\", { plainObjects: true }), { arrayFormat: \"comma\", encodeValuesOnly: true });\n\n\n\n// TypeError: Cannot convert object to primitive value\n\n\n\n```\n\n\n\n#### Fix\n\n\n\nApplied in a952e75 on `main` and released as v6.16.1: an element whose string coercion would fail is coerced to its primitive `valueOf`, if any, or else to `Object.prototype.toString`, so it renders as `[object Object]`, the same as any other object element already does under the comma format. Nested arrays are walked the way `join` walks them. Every input that did not previously throw serializes exactly as before, and a `toString` or `valueOf` that itself throws still propagates.\n\n\n\n### Affected versions\n\n\n\n`\u003e\u003d6.7.0 \u003c6.16.1`, fixed in v6.16.1.\n\n\n\nThe `join` path was introduced with the comma format in b84acba and first shipped in v6.7.0; v6.6.x and earlier ignore `arrayFormat: \u0027comma\u0027` and are not affected. The `encodeValuesOnly` `String()` site was introduced in 4c4b23d (v6.11.1); before that, the same input throws at `join`. Every release from v6.7.0 through v6.16.0 is affected.\n\n\n\n### Impact\n\n\n\nAn unauthenticated request can make any code path that re-serializes attacker-influenced data with `qs.stringify` and `arrayFormat: \u0027comma\u0027` (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 bare `http` request handler, the process exits, so the impact in that case depends on the application error handling rather than on qs. The default `arrayFormat` (`indices`) is not affected.","datePublished":"Oct 14, 2026, 10:05:24 PM","dateUpdated":"Oct 16, 2026, 8:17:48 PM","status":"PUBLISHED","baseScore":6.3,"baseScoreVersion":"4.0","baseScoreVector":"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","references":"https://github.com/ljharb/qs/security/advisories/GHSA-6pq8-jhm2-2vcw\nhttps://github.com/ljharb/qs/commit/a952e7519338ef0cfb25694a2988848f93333727\n","enisa_id":"EUVD-2026-101710\n","assigner":"harborist","epss":0.37,"dataProcessed":"Oct 27, 2026, 7:14:16 AM","vulnerabilityProduct":[{"id":"f46587cd-c9af-3d32-8c29-67bfc7f11c53","product":{"name":"qs","vendor":{"name":"ljharb"}},"product_version":"6.7.0 \u003c6.16.1"}],"vulnerabilityVendor":[{"id":"a2721e7a-daf3-3c96-9d1a-2133952d5ae2","vendor":{"name":"ljharb"}}]}}],"enisaIdAdvisory":[{"id":"0a419c98-42a8-313a-bd61-6d4598991145","advisory":{"id":"RHSA-2026:87077","description":"Red Hat Security Advisory: Red Hat Hardened Images RPMs Security Update","summary":"An update for Red Hat Hardened Images RPMs is now available.","datePublished":"Oct 21, 2026, 2:59:57 PM","dateUpdated":"Oct 21, 2026, 7:42:09 PM","baseScore":0.0,"references":"https://access.redhat.com/errata/RHSA-2026:87077\nhttps://security.access.redhat.com/data/csaf/v2/advisories/2026/rhsa-2026_87077.json\n","aliases":"CVE-2026-15577\nCVE-2026-33374\nCVE-2026-92539\nCVE-2026-93294\nCVE-2026-95502\nCVE-2026-100347\nCVE-2026-100348\nCVE-2026-100349\nCVE-2026-100351\nCVE-2026-100352\nCVE-2026-100353\nCVE-2026-100354\nCVE-2026-110816\n","source":{"id":9,"name":"csaf_redhat"},"advisoryProduct":[{"id":"5f1a0d9b-0fe1-3332-8c5f-7d2a272304e8","product":{"name":"Red Hat Hardened Images","vendor":{"name":"Red Hat"}}},{"id":"9ffad9db-9975-302f-bc87-180a0e507f2b","product":{"name":"grafana13.1-0:13.1.8-0.3.hum1@x86_64","vendor":{"name":"Red Hat"}}},{"id":"b3b55662-76eb-3a93-a447-3c0362fb32e6","product":{"name":"grafana13.1-0:13.1.8-0.3.hum1@src","vendor":{"name":"Red Hat"}}},{"id":"d9d9f30e-7c1f-3413-9095-a5f4054ec4a5","product":{"name":"grafana13.1-0:13.1.8-0.3.hum1@s390x","vendor":{"name":"Red Hat"}}},{"id":"da94b432-0233-3aa5-b005-60d231916edd","product":{"name":"grafana13.1-0:13.1.8-0.3.hum1@aarch64","vendor":{"name":"Red Hat"}}}]}},{"id":"1ed86306-aacf-3317-8227-cabda8b9ac93","advisory":{"id":"RHSA-2026:85266","description":"Red Hat Security Advisory: Red Hat Hardened Images RPMs Security Update","summary":"An update for Red Hat Hardened Images RPMs is now available.","datePublished":"Oct 19, 2026, 7:02:40 PM","dateUpdated":"Oct 21, 2026, 7:42:24 PM","baseScore":0.0,"references":"https://access.redhat.com/errata/RHSA-2026:85266\nhttps://security.access.redhat.com/data/csaf/v2/advisories/2026/rhsa-2026_85266.json\n","aliases":"CVE-2026-93450\nCVE-2026-100347\nCVE-2026-100348\nCVE-2026-100349\nCVE-2026-100351\nCVE-2026-100352\nCVE-2026-100353\nCVE-2026-100354\nCVE-2026-110816\n","source":{"id":9,"name":"csaf_redhat"},"advisoryProduct":[{"id":"39b28d33-c263-352c-909d-e66dfcea4619","product":{"name":"grafana13.2-0:13.2.3-0.3.hum1@aarch64","vendor":{"name":"Red Hat"}}},{"id":"60cc3524-7d6c-38c6-8cae-179b42ce169e","product":{"name":"grafana13.2-0:13.2.3-0.3.hum1@src","vendor":{"name":"Red Hat"}}},{"id":"bd3c067e-3a7e-3b44-bbcb-80a512e34e4d","product":{"name":"grafana13.2-0:13.2.3-0.3.hum1@x86_64","vendor":{"name":"Red Hat"}}},{"id":"c7342884-4506-3372-a476-1e94b785015b","product":{"name":"grafana13.2-0:13.2.3-0.3.hum1@s390x","vendor":{"name":"Red Hat"}}},{"id":"de0a7631-81a4-3778-ba4f-8437f287389b","product":{"name":"Red Hat Hardened Images","vendor":{"name":"Red Hat"}}}]}},{"id":"5ad7a41b-b834-3557-9018-eae8c0bdffa3","advisory":{"id":"msrc_CVE-2026-110816","description":"qs.stringify with arrayFormat comma throws TypeError on array elements that cannot be coerced to a string","datePublished":"Oct 17, 2026, 1:08:21 AM","dateUpdated":"Oct 17, 2026, 1:08:21 AM","baseScore":0.0,"references":"https://msrc.microsoft.com/csaf/vex/2026/msrc_cve-2026-110816.json\n","aliases":"CVE-2026-110816\n","source":{"id":20,"name":"csaf_microsoft"},"advisoryProduct":[{"id":"83d2fdd5-a001-33d3-be87-1e3ab199b34e","product":{"name":"3.0","vendor":{"name":"Wind River"}}},{"id":"e9f4f626-f76d-3fa2-9e8f-1d8123504bde","product":{"name":"Azure Linux","vendor":{"name":"Microsoft"}}},{"id":"f541e09b-366c-307e-8dd4-589627e8983b","product":{"name":"python-tensorboard","vendor":{"name":"Microsoft"}}}]}}]}