Skip to content

fix: restore array parsing for req.query repeated keys (#7147)#7181

Open
SAY-5 wants to merge 1 commit intoexpressjs:4.xfrom
SAY-5:fix-query-array-limit
Open

fix: restore array parsing for req.query repeated keys (#7147)#7181
SAY-5 wants to merge 1 commit intoexpressjs:4.xfrom
SAY-5:fix-query-array-limit

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 15, 2026

Closes #7147.

The bump to qs@~6.14.1 in 4.22.0 (#6972) pulled in qs's new default arrayLimit of 20, which causes the extended query parser to silently collapse repeated-key query strings with more than 20 values into an object (e.g. { "0": "a", "1": "b", ... }) instead of producing an array. This broke consumers that had been passing larger batches of repeated parameters through req.query.ids (the issue reporter hits it with ~20 tenancy IDs).

body-parser already got an opt-out path for the extended URL-encoded middleware, but the parseExtendedQueryString used by req.query for the 'extended' query parser still only passes allowPrototypes: true and otherwise inherits qs defaults — so the regression is only visible on req.query, which is what #7147 reports.

This PR restores the pre-6.14 behavior by passing arrayLimit: Infinity to qs.parse inside parseExtendedQueryString. Repeated-key values of any length round-trip back to an array, matching Express <= 4.21.x.

Test plan

  • Added a regression test in test/req.query.js that sends 25 repeated ids values and asserts req.query.ids is an array of 25 strings. Verified the test fails on 4.x without the fix and passes with it.
  • Full test/req.query.js suite: 11 passing.

If it would help, I'm happy to open a matching PR against 5.x — the same parseExtendedQueryString lives there with the same defaults.

Copy link
Copy Markdown
Contributor

@krzysdz krzysdz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Infinity completely removes protection from sending something like arr[999999]=x and allows creating large arrays by sending just 1 parameter with an index.

PR #7151 (to master) uses a value of 1000 (same as the parameter limit), which is a better idea, but it still relaxes the limit compared to qs 6.14.0.

)

qs 6.14 enforces a default `arrayLimit` of 20, which caused the
extended query parser to collapse query strings with more than 20
repeated values (e.g. `?ids=1&ids=2&...&ids=25`) into an object
instead of an array. This regressed in 4.22.0 (with the bump to
`qs@~6.14.1`) and broke existing consumers relying on the pre-6.14
behavior.

Pass `arrayLimit: Infinity` to `qs.parse` in
`parseExtendedQueryString` so repeated keys always produce arrays,
matching the behavior of Express \<= 4.21.x. Added a regression test
in `test/req.query.js` that sends 25 repeated values and asserts
they round-trip as an array.
@SAY-5 SAY-5 force-pushed the fix-query-array-limit branch from e8b025b to c0b4eaa Compare April 15, 2026 08:05
@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented Apr 15, 2026

Thanks @krzysdz — good catch. Updated to arrayLimit: 1000 to match PR #7151 and the parameter limit used elsewhere. That still lets apps pass repeated-key arrays up to 1000 elements (which covers the failing real-world case in the issue) while bounding single-parameter expansions like arr[999999]=x.

Also added a second regression test asserting that arr[9999]=x now collapses to an object instead of allocating a sparse array, so the arrayLimit bound stays covered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants