CVE-2026-110910
Received Received - Intake

Empty Array Parameter Injection in qs.js

Vulnerability report for CVE-2026-110910, including description, CVSS score, EPSS score, affected products, exploitability, helpful resources, and attack-flow context.

Publication date: 2026-10-27

Last updated on: 2026-10-27

Assigner: harborist

Description

### Summary `qs.stringify` with `allowEmptyArrays: true` writes the key of an empty array without encoding it, even though keys are encoded by default. A key that contains `&` (or the configured `delimiter`), `=`, or `#` ∴ becomes query string syntax instead of data, so a caller-supplied key name can add parameters to the serialized query string, or cut it short. ### Details In `lib/stringify.js`, the `allowEmptyArrays` branch returns `adjustedPrefix + '[]'` early, before the code that passes every other key through `encoder` and `formatter`. So `{ "x&k=v": ["1"] }` serializes as `x%26k%3Dv%5B0%5D=1`, but `{ "x&k=v": [] }` serializes as `x&k=v[]`. The early return applies at any depth (`{ "a": { "b&k=v": [] } }` gives `a[b&k=v][]`), under every `arrayFormat`, with `allowDots`, and with a custom `encoder`, which is never called for that key. With `encode: false` or `encodeValuesOnly: true`, keys are intentionally left unencoded on every path; those configurations are not affected. #### PoC ```js var qs = require("qs"); var query = qs.stringify({ q: "hi", "x&apiKey=evil&y": [] }, { allowEmptyArrays: true }); // "q=hi&x&apiKey=evil&y[]" qs.parse(query); // { q: "hi", x: "", apiKey: "evil", y: [""] } qs.stringify({ "x#": [], z: "1" }, { allowEmptyArrays: true }); // "x#[]&z=1": in a URL, everything after "#" becomes the fragment ``` #### Fix Applied in 234d505 on `main` and released as v6.17.0: the key of an empty array goes through `encoder` and `formatter` exactly as the key of any other value does, so `{ "x&apiKey=evil&y": [] }` now serializes as `x%26apiKey%3Devil%26y[]`. Keys that need no encoding serialize as before, with two exceptions that match every other path: the brackets of a nested key are now encoded (`a[b][]` becomes `a%5Bb%5D[]`, which `qs.parse` reads identically), and with `encodeDotInKeys`, a dot in the key becomes `%252E` instead of `%2E` (which `decodeDotInKeys` previously misread as nesting). ### Affected versions `>=6.12.0 <6.17.0`, fixed in v6.17.0. `allowEmptyArrays` was introduced in f22b2bc and first shipped in v6.12.0, with this early return. Every release from v6.12.0 through v6.16.1 is affected. Earlier versions have no `allowEmptyArrays` option and are not affected. ### Impact An application that passes an object whose key names come from untrusted input to `qs.stringify` with `allowEmptyArrays: true` (for example, to forward a parsed JSON body or user-selected fields to an upstream service) can have parameters injected into the resulting query string. The injected parameters are not keys of the object, so deleting or overwriting a key on the object (such as setting a trusted `apiKey` after copying the user's fields) does not remove them; whether the attacker's value or the application's wins depends on how the receiving side handles a duplicate parameter. A `#` in such a key ends the query string early when the result is placed in a URL. `allowEmptyArrays` is off by default, and only keys whose value (after any `filter`) is an empty array are affected.

CVSS Scores

EPSS Scores

Probability:
Percentile:

Meta Information

Published
2026-10-27
Last Modified
2026-10-27
Generated
2026-10-27
AI Q&A
2026-10-27
EPSS Evaluated
N/A
NVD
EUVD

Affected Vendors & Products

Showing 1 associated CPE
Vendor Product Version / Range
ljharb qs 6.12.0

Helpful Resources

Exploitability

CWE
CWE Icon
KEV
KEV Icon
CWE ID Description
CWE-116 The product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. As a result, the intended structure of the message is not preserved.

Attack-Flow Graph

AI Quick Actions

Instant insights powered by AI
Executive Summary

This vulnerability affects the qs library's stringify function when the allowEmptyArrays option is set to true. It allows keys containing special characters like &, =, or # to bypass URL encoding when paired with empty arrays. This can lead to query string parameter injection or early termination of the query string in URLs.

Detection Guidance

Check if your system uses qs library versions 6.12.0 to 6.16.1. Run npm list qs or check package.json for version. Test serialization of objects with empty arrays and special characters in keys using qs.stringify({ 'x&apiKey=evil&y': [] }, { allowEmptyArrays: true }). If output contains unencoded special characters like & or =, the system is vulnerable.

Impact Analysis

An application using qs.stringify with allowEmptyArrays: true on untrusted input could have parameters injected into the query string. Attackers could manipulate keys to add unintended parameters or truncate the query string using # characters. The impact depends on how the receiving service processes duplicate parameters.

Mitigation Strategies

Upgrade qs library to version 6.17.0 or later. If upgrading is not possible, avoid using the allowEmptyArrays option or sanitize object keys before passing them to qs.stringify. Review code that uses qs.stringify with allowEmptyArrays to ensure keys are trusted or properly encoded.

Chat Assistant

Ask questions about this CVE
Hi! I’m here to help you understand CVE-2026-110910. Ask me anything about the vulnerability, its impact, or mitigation strategies.
0/70

EPSS Chart