Read the docs
TI-2026-81027 Aliases CVE-2026-110910

Unencoded keys in qs.stringify allow query parameter injection

Priority LOW 28CWE-116Published · Updated

Key facts

Attack vector
Network
Privileges required
None
User interaction
None
Attack complexity
Low
Attack requirements
Present
Impact type
—
Confidentiality · integrity · availability
None · Low · None
Fix status
Partial Red Hat: 1 fixed, 35 without a fix

Attack profile from CVSS 4.0 · CNA. Fix status from CNA and Red Hat.

Summary

Versions of qs by ljharb from 6.12.0 before 6.12.6, from 6.13.0 before 6.13.4, from 6.14.0 before 6.14.3, from 6.15.0 before 6.15.4, and from 6.16.0 before 6.16.2 are affected. With allowEmptyArrays enabled, qs.stringify does not encode the key of an empty array, so & or = in that key becomes query string syntax (CWE-116). A remote attacker can inject parameters into the query string when an application builds keys from untrusted input.

Written with Claude Haiku 5.5 from the sources below · 2026-11-04

Description from the CNA

### 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 `#` therefore 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, and backported to v6.16.2, v6.15.4, v6.14.3, v6.13.4, and v6.12.6: 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.12.6`, fixed in v6.12.6 - `>=6.13.0 <6.13.4`, fixed in v6.13.4 - `>=6.14.0 <6.14.3`, fixed in v6.14.3 - `>=6.15.0 <6.15.4`, fixed in v6.15.4 - `>=6.16.0 <6.16.2`, fixed in v6.16.2 v6.17.0 and later are not affected. `allowEmptyArrays` was introduced in f22b2bc and first shipped in v6.12.0, with this early return. 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.

Why it matters now

Exploitation None reported CISA SSVC · not in CISA KEV
EPSS 0.00286 21st percentileScored 2026-11-07
Fix Partial qs (ljharb): 6.12.6, 6.13.4, 6.14.3 +2Red Hat: 1 advisoryRed Hat: 1 fixed, 35 without a fix

SSVC decision points

CISA ADP · SSVC 2.0.3

Exploitation
None
Automatable
No
Technical impact
Partial

The decision (Track, Attend, Act) also depends on your mission and well-being impact; see CISA's SSVC guide.

Affected products

VendorProductAffected versionsFixed inStatusSource
ljharbqs6.12.0 to before 6.12.6; 6.13.0 to before 6.13.4; 6.14.0 to before 6.14.3; 6.15.0 to before 6.15.4; 6.16.0 to before 6.16.26.12.6, 6.13.4, 6.14.3, 6.15.4, 6.16.2Patch availableCNA
  • qs Vendorljharb Affected 6.12.0 to before 6.12.6; 6.13.0 to before 6.13.4; 6.14.0 to before 6.14.3; 6.15.0 to before 6.15.4; 6.16.0 to before 6.16.2 Fixed in 6.12.6, 6.13.4, 6.14.3, 6.15.4, 6.16.2 Patch available CNA

Remediation

Upgrade qs to 6.12.6, 6.13.4, 6.14.3, 6.15.4, 6.16.2, or 6.17.0 and later, matching your release line. Red Hat Hardened Images is fixed by RHSA-2026:94794. Red Hat's plan is none available for Ansible Automation Orchestrator 2026, Cost Management On Premise, Cryostat 4, Migration Toolkit for Applications 8, Migration Toolkit for Containers, and other products.

Written with Claude Haiku 5.5 from the sources below · 2026-11-04

  • Fix · CNA qs (ljharb) Fixed in 6.12.6, 6.13.4, 6.14.3, 6.15.4, 6.16.2

Red Hat 1 advisory

  • RHSA-2026:94794 Released 2026-11-03 · Red Hat rating Important
    Red Hat Hardened Images RPMs Security Update
    • Red Hat Hardened Images grafana13.2-13.2.4-0.6.hum1@aarch64, grafana13.2-13.2.4-0.6.hum1@s390x, grafana13.2-13.2.4-0.6.hum1@src +1

Vendor assessments

Red Hat

Red Hat rating: Low. Red Hat's page for this CVE →

ProductStatusPlan or fix
Ansible Automation Orchestrator 2026AffectedNo fix yet: Fix deferred
Cost Management On PremiseAffectedNo fix yet: Fix deferred
Cryostat 4AffectedNo fix yet: Fix deferred
Migration Toolkit for Applications 8AffectedNo fix yet: Fix deferred
Migration Toolkit for ContainersAffectedNo fix yet: Fix deferred
Multicluster Engine for KubernetesAffectedNo fix yet: Fix deferred
Node HealthCheck OperatorAffectedNo fix yet: Fix deferred
OpenShift LightspeedAffectedNo fix yet: Fix deferred
OpenShift PipelinesAffectedNo fix yet: Fix deferred
OpenShift ServerlessAffectedNo fix yet: Fix deferred
OpenShift Service Mesh 3AffectedNo fix yet: Fix deferred
Red Hat Advanced Cluster Management for Kubernetes 2AffectedNo fix yet: Fix deferred
Red Hat Advanced Cluster Security 4AffectedNo fix yet: Fix deferred
Red Hat Ansible Automation Platform 2AffectedNo fix yet: Fix deferred
Red Hat Build of Podman DesktopAffectedNo fix yet: Fix deferred
Red Hat Connectivity Link 1AffectedNo fix yet: Fix deferred
Red Hat Data Grid 8AffectedNo fix yet: Fix deferred
Red Hat Developer Hub 1AffectedNo fix yet: Fix deferred
Red Hat Discovery 2AffectedNo fix yet: Fix deferred
Red Hat Enterprise Linux 10AffectedNo fix yet: Fix deferred
Red Hat Enterprise Linux 9AffectedNo fix yet: Fix deferred
Red Hat Enterprise Linux AI (RHEL AI) 3AffectedNo fix yet: Fix deferred
Red Hat OpenShift AI (RHOAI)AffectedNo fix yet: Fix deferred
Red Hat OpenShift Container Platform 4AffectedNo fix yet: Fix deferred
Red Hat OpenShift Container Platform 5AffectedNo fix yet: Fix deferred
Red Hat OpenShift Dev SpacesAffectedNo fix yet: Fix deferred
Red Hat OpenShift GitOpsAffectedNo fix yet: Fix deferred
Red Hat Openshift Data Foundation 4AffectedNo fix yet: Fix deferred
Red Hat Quay 3AffectedNo fix yet: Fix deferred
Red Hat Satellite 6AffectedNo fix yet: Fix deferred
Red Hat Trusted Profile AnalyzerAffectedNo fix yet: Fix deferred
Red Hat build of Apache Camel - HawtIO 4AffectedNo fix yet: Fix deferred
Red Hat build of Apache Camel for Spring Boot 4AffectedNo fix yet: Fix deferred
Secrets Management Console for Red Hat OpenShiftAffectedNo fix yet: Fix deferred
Self-service automation portal 2AffectedNo fix yet: Fix deferred
Red Hat Hardened ImagesFixed RHSA-2026:94794
Not affected: 15 products
  • Node HealthCheck Operator
  • Red Hat 3scale API Management Platform 2
  • Red Hat AMQ Broker 7
  • Red Hat Advanced Cluster Management for Kubernetes 2
  • Red Hat Ansible Automation Platform 2
  • Red Hat Ceph Storage 4
  • Red Hat Enterprise Linux 7
  • Red Hat Enterprise Linux 8
  • Red Hat Enterprise Linux 9
  • Red Hat Fuse 7
  • Red Hat Hardened Images
  • Red Hat JBoss Enterprise Application Platform 7
  • Red Hat OpenShift AI (RHOAI)
  • Red Hat OpenStack Platform 17.1
  • Red Hat Single Sign-On 7

Timeline

  1. 2026-10-27 Threatist record created from CVE-2026-110910
  2. 2026-10-27 Fix available: [email protected], [email protected], [email protected] +2 · CNA
  3. 2026-10-27 5 new references · CNA
  4. 2026-10-27 Priority changed: MEDIUM → LOW
  5. 2026-10-29 Affected versions changed · Red Hat
  6. 2026-10-29 CVSS score added · Red Hat
  7. 2026-10-30 Affected versions changed · Red Hat
  8. 2026-11-04 Fix available: RHSA-2026:94794 · Red Hat
  9. 2026-11-04 Fix available: Red Hat Hardened Images · Red Hat
  10. 2026-11-04 CISA SSVC decision points changed

References

  • TI-2026-74516 qs stringify throws TypeError on uncoercible array elements in comma format CVSS 4.0MEDIUM 6.3
  • TI-2026-56824 qs.stringify throws TypeError on objects with a non-callable constructor.isBuffer property CVSS 4.0MEDIUM 6.3
  • TI-2026-07665 qs.stringify crashes on null/undefined entries in comma-format arrays under encodeValuesOnly CVSS 4.0MEDIUM 6.3
  • TI-2026-56916 Resource allocation without limits in ljharb qs CVSS 4.0MEDIUM 6.3
  • TI-2026-69286 Prototype pollution in traverse set() modifies built-in prototypes CVSS 4.0MEDIUM 6.9

Sources