Skip to content

chore(deps): update dependency qs@<6.14.1 to >=6.17.1 [security] - autoclosed - #3847

Closed
renovate[bot] wants to merge 1 commit into
mainfrom
renovate-npm-qs-6.14.1-vulnerability
Closed

renovate[bot] wants to merge 1 commit into
mainfrom
renovate-npm-qs-6.14.1-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Mar 1, 2026 •

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
qs@<6.14.1 >=6.14.1 → >=6.17.1 age confidence

qs array-limit bypass via bracket-key comma parsing

CVE-2026-82562 / GHSA-x5fp-wj9c-mxmx

More information

Details

Summary

qs v6.15.3 allows bracket-key input to bypass arrayLimit and throwOnLimitExceeded when comma: true. The input a[]=1,2,3,4 succeeds with arrayLimit: 3, while the equivalent plain-key input is rejected.

Affected version tested:

qs v6.15.3
commit 18d085e919dae70c8f1b200ab99323058edab2c2
Details

parseArrayValue() enforces the comma limit only for flat values. The a[] form is marked non-flat, so its comma-separated value is wrapped after parsing and the inner array is not checked. A single parameter can therefore materialize arbitrarily large arrays.

PoC
const qs = require('qs')
const options = { comma: true, arrayLimit: 3, throwOnLimitExceeded: true }

const result = qs.parse('a[]=1,2,3,4', options)
console.log(result.a[0].length) // 4; expected RangeError

const big = qs.parse('a[]=' + '1,'.repeat(1000000) + '1', { comma: true, arrayLimit: 20 })
console.log(big.a[0].length) // 1000001

On v6.15.3, the first input parses successfully and the second creates an array with 1,000,001 elements. The equivalent a=1,2,3,4 input throws RangeError as expected.

Impact

An attacker who can supply a query string or form body can bypass configured array limits and force excessive memory allocation, causing denial of service. The limit must be applied after comma splitting and before the resulting array is wrapped.

Severity

  • CVSS Score: 6.3 / 10 (Medium)
  • Vector String: 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

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


qs: Denial of Service via Attacker Controlled isBuffer

CVE-2026-82417 / GHSA-4mjr-xmp4-gh2g

More information

Details

Summary

qs.stringify() calls utils.isBuffer() on every value it serializes, and utils.isBuffer() invokes obj.constructor.isBuffer(obj) without checking that it is callable. A value whose own constructor.isBuffer is a non-function makes qs call a non-callable and throw TypeError. Such a value is produced by qs.parse itself from an untrusted query string when plainObjects: true or allowPrototypes: true is set, so a pure-qs parse → stringify round-trip — no JSON.parse — turns an unauthenticated query string into an uncaught throw.

An attacker-controlled parse input reaches the host application's availability asset — via qs's own recommended plainObjects mitigation — and triggers an uncaught exception during a parse → stringify round-trip.

Details

utils.isBuffer runs at lib/stringify.js:127 for every serialized value:

if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) { ... }

utils.isBuffer (lib/utils.js:327-333) invokes obj.constructor.isBuffer without verifying it is callable:

var isBuffer = function isBuffer(obj) {
    if (!obj || typeof obj !== 'object') { return false; }
    return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
};

constructor and isBuffer are ordinary keys. qs.parse with plainObjects: true or allowPrototypes: true keeps them as own properties, so the parsed value carries a non-function constructor.isBuffer; stringify then calls a non-callable and throws TypeError. By contrast utils.isRegExp uses a brand check (Object.prototype.toString); the missing guard here is an internal inconsistency, not a platform limitation.

Trust Boundary Note

qs.stringify alone treats its input as caller-constructed, so serializing a hostile object could be argued outside its contract. This report does not depend on that framing: the malicious shape is produced by qs.parse, whose input is untrusted by design. qs.parse normally strips a constructor key via its prototype guard, but with the documented options plainObjects: true or allowPrototypes: true the key survives and lands as an own property. Feeding the parsed object back into qs.stringify — the standard round-trip in gateways and request-forwarders — then hits the unchecked call.

PoC

poc02c_isBuffer_qs_only_roundtrip.js — pure-qs chain, no JSON.parse; an untrusted query string alone reaches the throw:

'use strict';
var qs = require('qs');

var untrustedQueryString = 'x%5Bconstructor%5D%5BisBuffer%5D=y'; // x[constructor][isBuffer]=y

var parsed = qs.parse(untrustedQueryString, { plainObjects: true });
console.log('[parse] kept constructor key:', JSON.stringify(parsed));

try {
    qs.stringify(parsed);
    console.log('[stringify] no throw (unexpected)');
} catch (e) {
    console.log('[stringify] DoS reproduced ->', e.constructor.name + ':', e.message);
}

poc02_isBuffer.js — the minimal defect:

'use strict';
var qs = require('qs');
try {
    qs.stringify(JSON.parse('{"a":{"constructor":{"isBuffer":"x"}}}'));
} catch (e) {
    console.log('[A] DoS reproduced ->', e.constructor.name + ':', e.message);
}

poc02b_isBuffer_async_crash.js — worker death in an async sink:

'use strict';
var qs = require('qs');

function handleRequestAsync(clientJsonBody) {
    try {
        setImmediate(function () {                 // async continuation, outside the try
            qs.stringify(JSON.parse(clientJsonBody)); // throws here, uncaught
        });
        console.log('[handler] returned 200 synchronously; async work scheduled');
    } catch (e) {
        console.log('[handler] caught synchronously (will NOT happen):', e.message);
    }
}
process.on('exit', function (code) {
    console.log('[proc] process exiting with code:', code);
});
handleRequestAsync('{"filters":{"constructor":{"isBuffer":"x"}}}');
Execution Steps
cd poc
npm install qs@6.15.3
node poc02c_isBuffer_qs_only_roundtrip.js  # pure qs parse->stringify -> TypeError
node poc02_isBuffer.js                      # minimal defect -> TypeError inside stringify
node poc02b_isBuffer_async_crash.js         # async sink -> uncaught throw -> exit code 1
Reproduction Evidence

poc02c_isBuffer_qs_only_roundtrip.js :

[parse] kept constructor key: {"x":{"constructor":{"isBuffer":"y"}}}
[stringify] DoS reproduced -> TypeError: obj.constructor.isBuffer is not a function

poc02_isBuffer.js:

[A] DoS reproduced -> TypeError: obj.constructor.isBuffer is not a function

poc02b_isBuffer_async_crash.js :

[handler] returned 200 synchronously; async work scheduled
[proc] process exiting with code: 1
TypeError: obj.constructor.isBuffer is not a function
    at Object.isBuffer (.../qs/lib/utils.js:332:78)
    at stringify (.../qs/lib/stringify.js:127:45)
=== EXIT CODE: 1 ===

The pure-qs round-trip shows the malicious shape originates from qs.parse of an untrusted query string, with no JSON.parse. The synchronous try/catch in the async case does not catch the throw; the process exits with code 1, denying service to all requests on that worker.

Impact

An unauthenticated request degrades any endpoint that re-serializes deserialized client data with qs.stringify. The primary impact is a per-request failure: the handler throws and the framework returns HTTP 500. Where the call sits in an unguarded async continuation, the throw escapes and the worker process exits, denying service to all requests it was handling, which means a higher impact that depends on the application's error handling, not on qs.

Recommended Fix

Replace the duck-type with a brand check mirroring utils.isRegExp:

var isBuffer = function isBuffer(obj) {
    if (!obj || typeof obj !== 'object') { return false; }
    if (typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function') {
        return Buffer.isBuffer(obj);
    }
    return Object.prototype.toString.call(obj) === '[object Uint8Array]';
};

If duck-typing must remain, require typeof obj.constructor.isBuffer === 'function' before invoking and wrap the call in try/catch.

Severity

  • CVSS Score: 6.3 / 10 (Medium)
  • Vector String: 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

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


qs : qs.stringify with arrayFormat 'comma' throws an uncaught TypeError on array elements carrying a non-callable own toString (DoS)

CVE-2026-110816 / GHSA-6pq8-jhm2-2vcw

More information

Details

Summary

qs.stringify(obj, { arrayFormat: 'comma' }) throws an uncaught TypeError: Cannot convert object to primitive value when an array in obj contains an element that carries an own, non-callable toString property (for example { a: [ { toString: 'x' } ] }). A remote, unauthenticated attacker who can influence an object that the application later re-serializes with the comma array format triggers the throw. In a service that lacks a synchronous error boundary around the serialization call, the uncaught exception crashes the worker process, producing a denial of service.

Root Cause

When arrayFormat: 'comma' is selected, the comma branch collapses the whole array into a single value via Array.prototype.join, or, under encodeValuesOnly: true, maps each element through the value encoder before joining. Both paths perform an implicit string coercion (ToPrimitive with hint "string") on each element. For an object whose own toString is a non-callable value, coercion skips the shadowed non-callable toString, falls through to Object.prototype.valueOf (which returns the object rather than a primitive), and throws. The comma branch runs this coercion before the per-element null and skip handling in the main loop, so nothing downstream can neutralize the hostile element, and the throw is never caught inside the library.

lib/stringify.js  (comma-array branch)
  line 152-154: obj = utils.maybeMap(obj, function (v) { return v == null ? v : encoder(v); });  // encodeValuesOnly path
  line 156:     objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];   // default comma path
lib/utils.js
  line 292:     string = String(str);   // value encoder coercion reached via the encodeValuesOnly path
Impact

Prerequisites: the application calls qs.stringify with arrayFormat: 'comma' (a documented, supported option) on an object whose shape can be influenced by attacker input. Attacker-controllable sources include qs.parse(input, { allowPrototypes: true }), which retains a toString segment (Express 4's default query parser, Express 5's extended query parser, and body-parser's extended urlencoded parser all set it), qs.parse(input, { plainObjects: true }), whose null-prototype elements throw even without a toString key (eg, a[][b]=c), and JSON.parse of a request body, which needs no qs parse option at all. No authentication or user interaction is required. Demonstrated capability: a single request forces an uncaught synchronous TypeError in the serialization call. In a naive single-process Node service with no synchronous error boundary, this crashes the process and takes the service offline (availability impact). Under a framework such as Express that traps synchronous handler throws, the plausible outcome is a per-request 500 rather than a full outage; that lower-impact case is noted but not the worst credible supported deployment. There is no confidentiality or integrity impact, no memory unsafety, and no prototype pollution.

Proof of Concept

Install qs at the affected version (for example 6.16.0) and run the following script with Node.js. No network setup is required; it demonstrates the throw in isolation.

var qs = require('qs');

// Source A: qs.parse with allowPrototypes retains the hostile toString segment
qs.stringify(qs.parse('a[0][toString]=x', { allowPrototypes: true }), { arrayFormat: 'comma' });

// Source B: a JSON request body, no qs parse option needed
qs.stringify(JSON.parse('{"a":[{"toString":"x"}]}'), { arrayFormat: 'comma' });

// Also affected: the encodeValuesOnly sub-path
qs.stringify(JSON.parse('{"a":[{"toString":"x"}]}'), { arrayFormat: 'comma', encodeValuesOnly: true });
A default-join (allowPrototypes) => THREW: TypeError: Cannot convert object to primitive value
B default-join (JSON.parse) => THREW: TypeError: Cannot convert object to primitive value
C encodeValuesOnly path => THREW: TypeError: Cannot convert object to primitive value
N2 callable toString => NO THROW; output="a=z"
N3 isBuffer vector (CVE-2026-82417) => NO THROW; output="a%5Bconstructor%5D%5BisBuffer%5D=x"
qs version: 6.16.0
Attack Chain
  1. Exposure: A remote, unauthenticated request reaches an endpoint whose handler eventually serializes attacker-influenced data with qs.stringify(obj, { arrayFormat: 'comma' }).
  2. Control: The attacker supplies data that becomes { a: [ { toString: <non-callable value> } ] }, either via a[0][toString]=x parsed with allowPrototypes, or via a JSON body {"a":[{"toString":"x"}]}.
  3. Path: In stringify, the primitive/buffer guard at lib/stringify.js:134 is false for an array, so control reaches the comma branch at lib/stringify.js:149.
  4. Guard: On the encodeValuesOnly path, the closure v == null ? v : encoder(v) at lib/stringify.js:152-154 passes only null/undefined through; a non-null object still reaches the encoder. The default path skips that closure entirely and reaches obj.join(',') at lib/stringify.js:156 with no guard at all.
  5. Primitive: The element is coerced to a string (Array.prototype.join, or String(str) at lib/utils.js:292). ToPrimitive skips the non-callable own toString, valueOf returns the object, and a TypeError is thrown.
  6. Result: The uncaught synchronous exception propagates out of the serialization call, failing the request and, in a service without a synchronous error boundary, crashing the process (denial of service).
Bypass Evidence

This is a different element type on the code path CVE-2026-8723 (GHSA-q8mj-m7cp-5q26) patched, plus the default comma path, which that fix never covered. CVE-2026-8723 addressed a TypeError crash on null/undefined entries in the comma plus encodeValuesOnly path. Its fix (commit 21f80b3) wraps the encoder in function (v) { return v == null ? v : encoder(v); }, so it only passes null and undefined through. A non-null element with a hostile own toString fails the v == null test, so the encoder still runs and still throws; the encodeValuesOnly case (case C above) throws on the exact fixed code. The default comma path (encodeValuesOnly unset, the library default) never entered that fix at all: git log -S "obj.join(','" -- lib/stringify.js shows no security fix has ever touched the obj.join(',') line, and cases A and B throw with encodeValuesOnly unset. The related isBuffer hardening for CVE-2026-82417 (commit e83d321) is a different sink at the lib/stringify.js:134 guard, which is never entered for the array element; the negative control {a:{constructor:{isBuffer:'x'}}} serializes cleanly. Disproof attempts that failed: a valueOf-only object does not throw (it serializes to [object Object]), confirming the trigger is an element with no callable toString (an own non-callable toString, or a null-prototype object with no toString at all, as qs.parse produces under plainObjects); nested arrays ({"a":[[{"toString":"x"}]]}) throw the same way; a callable toString serializes cleanly; and the default (non-comma) array format serializes cleanly, confirming the comma format is required. All positive and negative cases were reproduced on the exact published 6.16.0 artifact.

Affected Versions
  • Ecosystem: npm
  • Package: qs
  • Confirmed affected range: >= 6.7.0, <= 6.16.0
  • Latest release checked: 6.16.0 (npm latest; git tag v6.16.0)
  • Fix status: fixed in 6.16.1 (a952e75)

The arrayFormat: 'comma' join sink was introduced in qs 6.7.0, so 6.7.0 is the lower boundary; releases before 6.7.0 lack the sink. No released version fixes this vector, and the latest published release (6.16.0) reproduces the throw, so the closed upper bound <= 6.16.0 covers every affected release. The encodeValuesOnly sub-path was added later, but the default comma-join vector already affects 6.7.0, so 6.7.0 governs the lower boundary.

Suggested Fix

The comma array serialization must not allow an implicit string coercion of an array element to throw an uncaught exception. Coercion of each comma element should be performed defensively (for example by wrapping the join and per-element encode so that a coercion failure is caught and handled), and this protection must cover both the default obj.join(',') path and the encodeValuesOnly encoder path, not only the previously patched null/undefined case. As an interim mitigation without a code change, applications can avoid arrayFormat: 'comma' when serializing data derived from untrusted input, sanitize parsed objects (avoid allowPrototypes/plainObjects on untrusted input and strip unexpected own properties), or wrap qs.stringify calls in a synchronous error boundary so a coercion failure cannot crash the process.

Reported by zx (GitHub: @​manus-pi).


Independent report by @​Lucidsec

The following was reported separately, after this advisory, and is merged here as a duplicate.

Summary

In project qs, in versions >= 6.7.0, <= 6.16.0 (every version that supports arrayFormat: 'comma'), qs.stringify with arrayFormat: 'comma' can throw an uncaught TypeError: Cannot convert object to primitive value when an array element has a non-callable own toString. It is fixed in 6.16.1. Related: CWE-248 and CWE-704.

Technical Details

qs.stringify with arrayFormat: 'comma' joins an array at lib/stringify.js:156 via obj.join(','). An element whose own toString is not callable makes Array.prototype.join throw. There is no type check and no catch on that path.

A second path exists with encodeValuesOnly: at lib/stringify.js:151-154, maybeMap only skips v == null, then lib/utils.js:292 does String(str) and throws the same TypeError (this second site exists since v6.11.1; before that, the same input throws at join).

Who can trigger: someone who can shape an array element passed to stringify. The host must use non-default arrayFormat: 'comma'. Default arrayFormat indices does not fold arrays and is not affected. A parse-then-stringify path also needs plainObjects: true (null-prototype elements from lib/parse.js:200) or allowPrototypes: true (which Express 4's default query parser, Express 5's extended query parser, and body-parser's extended urlencoded parser all set). Default qs.parse('a[0][toString]=x') returns {} because the prototype guard drops toString. Direct JSON handed to stringify can supply {"a":[{"toString":"x"}]}.

Cause: the comma fold at lib/stringify.js:149-156 collapses the array into a single value before the main loop at lib/stringify.js:172-212, so skipNulls and strictNullHandling only ever see the joined value, never individual elements. isNonNullishPrimitive / isBuffer at lib/stringify.js:134 inspect the whole value, not each element. A normal object uses Object.prototype.toString and becomes [object Object]. An own non-callable toString is skipped, valueOf returns the object, and join throws. (The skipped TODO test at test/stringify.js:684-689 uses a plain { b: 1 } element, which does not throw; it covers the separate question of what comma format should output for object elements, not this crash.) Earlier comma crash fixes did not cover object elements.

Impact

One small input makes that serialization path throw a synchronous, catchable TypeError. Behind a framework error boundary (eg, a synchronous Express handler), the request fails with a 500 and the process survives. In a host with no error boundary (eg, a bare http.createServer handler), the uncaught exception exits the process (the client sees ECONNRESET). Availability only.

Proof of Concept
Show the proof of concept

Checked on the latest commit that was checked: 07b1d4d82c8f9301c105ea4b94fa2302cfd6e8b4. Still present. Demonstrated.

  • Payload {"a":[{"toString":"x"}]} throws at lib/stringify.js:156.
  • Baseline {"a":["x","y"]} returns 200 with body a=x%2Cy.
  • A plain object element stringifies to a=%5Bobject%20Object%5D and does not throw.
  • encodeValuesOnly: true throws via utils.js:292.
  • plainObjects parse plus comma throws.
Suggested Fix

Before join, map elements with the existing primitive check; skip or replace non-primitives so join cannot throw. On the encodeValuesOnly path, do not send non-primitives into String(). Optionally guard lib/utils.js:292. Add new regression tests.

Severity

  • CVSS Score: 6.3 / 10 (Medium)
  • Vector String: 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

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

ljharb/qs (qs@<6.14.1)

v6.17.1

Compare Source

  • [Fix] parse: interpretNumericEntities: decode code points above U+FFFF as surrogate pairs (#​640)
  • [Fix] parse: respect plainObjects for [] with parseArrays: false (#​639)
  • [Fix] utils: merge: count the elements of a sparse array against arrayLimit, not its holes
  • [Fix] parse: guard bracket-wrapped prototype keys at depth 0 (#​638)
  • [Refactor] parse: extract wrapping-bracket stripping helper
  • [readme] document that depth: 0 and depth: false keep keys flat
  • [Tests] parse: pin depth-0 bracket stripping and prototype keys kept by allowPrototypes/plainObjects

v6.17.0

Compare Source

  • [New] stringify: add WHATWG format (#​623)
  • [Fix] stringify: do not sort the caller's filter array in place (#​637)
  • [Fix] parse: copy an own __proto__ key as data (#​636)
  • [Fix] parse: decode percent-encoded dots case-insensitively (#​635)
  • [Fix] stringify: encode keys when allowEmptyArrays is set (#​561)
  • [Fix] parse: preserve comma arrays when interpreting numeric entities (#​630)
  • [Fix] parse: allow scalar fields with a zero array limit (#​627)
  • [Fix] parse: do not count an existing comma array toward arrayLimit when duplicates discards or replaces it
  • [Fix] utils: encode: encode lone surrogates as U+FFFD instead of consuming the next code unit (#​624)
  • [eslint] fix indentation
  • [readme] document the encoder's format argument
  • [meta] add changelog acknowledgement
  • [meta] fix changelog indents
  • [Dev Deps] update eslint, evalmd, npmignore
  • [Tests] stringify: pin allowEmptyArrays output for keys that need no encoding
  • [Tests] stringify: pin sort order for nested keys selected by an array filter
  • [Tests] parse: cover interpretNumericEntities across value shapes, keys, and the charset sentinel
  • [Tests] parse: cover more input that builds no array at a zero or negative arrayLimit
  • [Tests] parse: cover comma with a zero or negative arrayLimit, and combining a full comma array
  • [Tests] parse: pin the behavior of a zero or negative arrayLimit
  • [Tests] utils/stringify: pin ~, *, and parens encoding in RFC3986 and RFC1738

v6.16.2

Compare Source

  • [Fix] stringify: encode keys when allowEmptyArrays is set (#​561)
  • [meta] use double quotes for better OS support
  • [Dev Deps] update evalmd, npmignore
  • [Tests] stringify: pin allowEmptyArrays output for keys that need no encoding

v6.16.1

Compare Source

  • [Fix] parse: do not mutate an object input
  • [Fix] stringify: stop re-encoding structural separator dots when encodeDotInKeys is set (#​564)
  • [Fix] stringify: arrayFormat: 'comma': pass the full encoder arguments with encodeValuesOnly
  • [Fix] utils: encode + as %2B in iso-8859-1 mode so values round-trip (#​565)
  • [Fix] parse: only convert top-level dots to brackets when allowDots is on (#​621)
  • [Fix] stringify: ignore inherited array format names (#​622)
  • [Fix] stringify: arrayFormat: 'comma': do not throw on elements with no callable toString
  • [Fix] utils: merge: seed an overflow container's index from its own keys, not just the source
  • [Fix] utils: merge: keep a strictMerge conflict container's index and arrayLimit correct
  • [Fix] parse: only treat [] as array syntax when it ends the key
  • [Perf] decode: skip decoders when there is no percent sign (#​583)
  • [Robustness] utils: merge: apply arrayLimit to the two-element array built for colliding values
  • [Robustness] parse: bound the nesting added by repeated strictMerge conflicts (credit @​Yeaseen)
  • [Docs] document that qs and flat parsers disagree about parameter names
  • [Docs] clarify that throwOnLimitExceeded limits each array, not the total number of values
  • [Docs] clarify 6.14.1/6.15.2 parse bracket behavior change (#​567, #​568)
  • [meta] fix changelog indents
  • [actions] set least-privilege cache-mode
  • [Tests] utils: decode: add missing cases
  • [Tests] parse: characterize the ]= split when an = precedes any bracket group (#​620)
  • [Tests] parse: allowDots: cover stray close brackets before a dot
  • [Dev Deps] update @ljharb/eslint-config, eslint, tape

v6.16.0

Compare Source

  • [New] stringify: add a depth option to bound recursion depth (default Infinity)
  • [Fix] stringify: serialize Date values when a filter is provided
  • [Fix] parse: enforce arrayLimit on comma groups under []= when throwOnLimitExceeded is set
  • [Fix] parse: flatten a collection appended to an overflowed array (#​571)
  • [Fix] utils: isBuffer: do not invoke a non-callable constructor.isBuffer
  • [Fix] stringify: do not let allowEmptyArrays skip cycle detection (or drop own keys) on an empty array with own properties
  • [Fix] stringify: encode dots in a top-level key with a primitive value when encodeDotInKeys is set (#​562)
  • [Docs] threat model: clarify stringify deep-nesting DoS is caller-bounded
  • [Docs] clarify arrayLimit is a representation threshold, not an element-count cap
  • [Tests] parse: remove a test that pinned []= comma groups escaping arrayLimit
  • [Tests] stringify: pin current encodeDotInKeys separator-dot behavior
  • [Dev Deps] update @ljharb/eslint-config, eslint
  • [Dev Deps] update eslint, evalmd

v6.15.4

Compare Source

  • [Fix] stringify: encode keys when allowEmptyArrays is set (#​561)
  • [meta] use double quotes for better OS support
  • [Dev Deps] update @ljharb/eslint-config, evalmd, npmignore, tape
  • [Tests] stringify: pin allowEmptyArrays output for keys that need no encoding

v6.15.3

Compare Source

  • [Fix] parse: enforce throwOnLimitExceeded for cumulative array growth via combine/merge
  • [Fix] utils: respect encoding of surrogate pairs across chunks (#​559)
  • [Robustness] parse: throw the arrayLimit error before splitting oversized comma values
  • [Robustness] utils.merge / utils.assign: avoid invoking __proto__ setter when copying own properties
  • [Robustness] utils: enforce arrayLimit consistently across merge's array paths
  • [Perf] utils: make compact O(n) via a side-channel visited-set instead of Array.indexOf
  • [Deps] update side-channel
  • [Dev Deps] update eslint, mock-property, tape
  • [Tests] parse: characterize current lenient handling of unbalanced bracket keys (#​558)

v6.15.2

Compare Source

  • [Fix] stringify: skip null/undefined entries in arrayFormat: 'comma' + encodeValuesOnly instead of crashing in encoder
  • [Fix] stringify: use configured delimiter after charsetSentinel (#​555)
  • [Fix] stringify: apply formatter to encoded key under strictNullHandling (#​554)
  • [Fix] stringify: skip null/undefined filter-array entries instead of crashing in encoder (#​551)
  • [Fix] parse: handle nested bracket groups and add regression tests (#​530); changes output for some unbalanced bracket keys (see #​558)
  • [readme] fix grammar (#​550)
  • [Dev Deps] update @ljharb/eslint-config
  • [Tests] add regression tests for keys containing percent-encoded bracket text

v6.15.1

Compare Source

  • [Fix] parse: parameterLimit: Infinity with throwOnLimitExceeded: true silently drops all parameters
  • [Deps] update @ljharb/eslint-config
  • [Dev Deps] update @ljharb/eslint-config, iconv-lite
  • [Tests] increase coverage

v6.15.0

Compare Source

  • [New] parse: add strictMerge option to wrap object/primitive conflicts in an array (#​425, #​122)
  • [Fix] duplicates option should not apply to bracket notation keys (#​514)

v6.14.3

Compare Source

  • [Fix] stringify: encode keys when allowEmptyArrays is set (#​561)
  • [meta] use double quotes for better OS support
  • [Deps] update side-channel
  • [Dev Deps] update @ljharb/eslint-config, es-value-fixtures, eslint, evalmd, mock-property, npmignore, tape
  • [Tests] stringify: pin allowEmptyArrays output for keys that need no encoding

v6.14.2

Compare Source

  • [Fix] parse: mark overflow objects for indexed notation exceeding arrayLimit (#​546)
  • [Fix] arrayLimit means max count, not max index, in combine/merge/parseArrayValue
  • [Fix] parse: throw on arrayLimit exceeded with indexed notation when throwOnLimitExceeded is true (#​529)
  • [Fix] parse: enforce arrayLimit on comma-parsed values
  • [Fix] parse: fix error message to reflect arrayLimit as max index; remove extraneous comments (#​545)
  • [Robustness] avoid .push, use void
  • [readme] document that addQueryPrefix does not add ? to empty output (#​418)
  • [readme] clarify parseArrays and arrayLimit documentation (#​543)
  • [readme] replace runkit CI badge with shields.io check-runs badge
  • [meta] fix changelog typo (arrayLength → arrayLimit)
  • [actions] fix rebase workflow permissions

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added the dependencies Pull requests that update a dependency label Mar 1, 2026
@netlify

netlify Bot commented Mar 1, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for brilliant-pasca-3e80ec canceled.

Name Link
🔨 Latest commit 11dfdc0
🔍 Latest deploy log https://app.netlify.com/projects/brilliant-pasca-3e80ec/deploys/6ae31be58310681fa7bf20d7

@github-actions

github-actions Bot commented Mar 1, 2026 •

Copy link
Copy Markdown

🚀 Performance Test Results

Test Configuration:

  • VUs: 4
  • Duration: 1m0s

Test Metrics:

  • Requests/s: 46.39
  • Iterations/s: 15.47
  • Failed Requests: 0.00% (0 of 2789)
📜 Logs

> performance@1.0.0 run-tests:testenv /home/runner/work/rafiki/rafiki/test/performance
> ./scripts/run-tests.sh -e test -k -q --vus 4 --duration 1m

Cloud Nine GraphQL API is up: http://localhost:3101/graphql
Cloud Nine Wallet Address is up: http://localhost:3100/
Happy Life Bank Address is up: http://localhost:4100/
cloud-nine-wallet-test-backend already set
cloud-nine-wallet-test-auth already set
happy-life-bank-test-backend already set
happy-life-bank-test-auth already set
     data_received..................: 1.0 MB 17 kB/s
     data_sent......................: 2.1 MB 36 kB/s
     http_req_blocked...............: avg=7.96µs   min=1.36µs   med=4.85µs   max=2.57ms   p(90)=6.39µs   p(95)=7.18µs  
     http_req_connecting............: avg=416ns    min=0s       med=0s       max=716.08µs p(90)=0s       p(95)=0s      
     http_req_duration..............: avg=85.62ms  min=6.8ms    med=57.94ms  max=893.96ms p(90)=152.1ms  p(95)=225.58ms
       { expected_response:true }...: avg=85.62ms  min=6.8ms    med=57.94ms  max=893.96ms p(90)=152.1ms  p(95)=225.58ms
     http_req_failed................: 0.00%  ✓ 0        ✗ 2789
     http_req_receiving.............: avg=91.7µs   min=20.11µs  med=82.72µs  max=1.61ms   p(90)=115.06µs p(95)=155.09µs
     http_req_sending...............: avg=34.67µs  min=7.56µs   med=23.37µs  max=2.83ms   p(90)=35.69µs  p(95)=53.16µs 
     http_req_tls_handshaking.......: avg=0s       min=0s       med=0s       max=0s       p(90)=0s       p(95)=0s      
     http_req_waiting...............: avg=85.5ms   min=6.67ms   med=57.77ms  max=893.9ms  p(90)=151.86ms p(95)=225.46ms
     http_reqs......................: 2789   46.38656/s
     iteration_duration.............: avg=258.32ms min=129.43ms med=210.77ms max=1.33s    p(90)=400.44ms p(95)=519.71ms
     iterations.....................: 930    15.46773/s
     vus............................: 4      min=4      max=4 
     vus_max........................: 4      min=4      max=4 

@renovate renovate Bot changed the title chore(deps): update dependency qs@&lt;6.14.1 to >=6.15.0 [security] chore(deps): update dependency qs@&lt;6.14.1 to >=6.14.2 [security] Mar 1, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch from cb07b7a to 99b7163 Compare March 1, 2026 21:08
@renovate renovate Bot changed the title chore(deps): update dependency qs@&lt;6.14.1 to >=6.14.2 [security] chore(deps): update dependency qs@&lt;6.14.1 to >=6.15.0 [security] Mar 5, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch 2 times, most recently from e2788d9 to c2f7e09 Compare March 5, 2026 09:57
@renovate renovate Bot changed the title chore(deps): update dependency qs@&lt;6.14.1 to >=6.15.0 [security] chore(deps): update dependency qs@&lt;6.14.1 to >=6.14.2 [security] Mar 5, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch from c2f7e09 to 04b8130 Compare March 5, 2026 17:41
@renovate renovate Bot changed the title chore(deps): update dependency qs@&lt;6.14.1 to >=6.14.2 [security] chore(deps): update dependency qs@&lt;6.14.1 to >=6.15.0 [security] Mar 5, 2026
@renovate renovate Bot changed the title chore(deps): update dependency qs@&lt;6.14.1 to >=6.15.0 [security] chore(deps): update dependency qs@<6.14.1 to >=6.15.1 [security] Apr 15, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch from 04b8130 to 550a1a3 Compare April 15, 2026 22:05
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch 2 times, most recently from 9b1d0ec to 9c74e25 Compare May 9, 2026 23:48
@renovate renovate Bot changed the title chore(deps): update dependency qs@<6.14.1 to >=6.15.1 [security] chore(deps): update dependency qs@<6.14.1 to >=6.15.2 [security] Jun 3, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch from 9c74e25 to 9ca9c96 Compare June 3, 2026 14:58
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch from 9ca9c96 to ea33f2e Compare October 3, 2026 23:03
@renovate renovate Bot changed the title chore(deps): update dependency qs@<6.14.1 to >=6.15.2 [security] chore(deps): update dependency qs@<6.14.1 to >=6.16.0 [security] Oct 3, 2026
@renovate renovate Bot changed the title chore(deps): update dependency qs@<6.14.1 to >=6.16.0 [security] chore(deps): update dependency qs@<6.14.1 to >=6.16.1 [security] Oct 25, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch 2 times, most recently from c76df89 to c5e907b Compare October 27, 2026 07:14
@renovate renovate Bot changed the title chore(deps): update dependency qs@<6.14.1 to >=6.16.1 [security] chore(deps): update dependency qs@<6.14.1 to >=6.17.0 [security] Oct 27, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch 3 times, most recently from 9689d88 to d2eb656 Compare October 29, 2026 03:51
@renovate renovate Bot changed the title chore(deps): update dependency qs@<6.14.1 to >=6.17.0 [security] chore(deps): update dependency qs@<6.14.1 to >=6.17.1 [security] Oct 29, 2026
@renovate
renovate Bot force-pushed the renovate-npm-qs-6.14.1-vulnerability branch from d2eb656 to 11dfdc0 Compare October 29, 2026 10:11
@renovate renovate Bot changed the title chore(deps): update dependency qs@<6.14.1 to >=6.17.1 [security] chore(deps): update dependency qs@<6.14.1 to >=6.17.1 [security] - autoclosed Oct 29, 2026
@renovate renovate Bot closed this Oct 29, 2026
@renovate
renovate Bot deleted the renovate-npm-qs-6.14.1-vulnerability branch October 29, 2026 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants