Skip to content

Conversation

@renovate
Copy link
Contributor

@renovate renovate bot commented Jan 1, 2026

This PR contains the following updates:

Package Change Age Confidence
qs 6.13.16.14.1 age confidence

GitHub Vulnerability Alerts

CVE-2025-15284

Summary

The arrayLimit option in qs does not enforce limits for bracket notation (a[]=1&a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit for DoS protection are vulnerable.

Details

The arrayLimit option only checks limits for indexed notation (a[0]=1&a[1]=2) but completely bypasses it for bracket notation (a[]=1&a[]=2).

Vulnerable code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = utils.combine([], leaf);  // No arrayLimit check
}

Working code (lib/parse.js:175):

else if (index <= options.arrayLimit) {  // Limit checked here
    obj = [];
    obj[index] = leaf;
}

The bracket notation handler at line 159 uses utils.combine([], leaf) without validating against options.arrayLimit, while indexed notation at line 175 checks index <= options.arrayLimit before creating arrays.

PoC

Test 1 - Basic bypass:

npm install qs
const qs = require('qs');
const result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4&a[]=5&a[]=6', { arrayLimit: 5 });
console.log(result.a.length);  // Output: 6 (should be max 5)

Test 2 - DoS demonstration:

const qs = require('qs');
const attack = 'a[]=' + Array(10000).fill('x').join('&a[]=');
const result = qs.parse(attack, { arrayLimit: 100 });
console.log(result.a.length);  // Output: 10000 (should be max 100)

Configuration:

  • arrayLimit: 5 (test 1) or arrayLimit: 100 (test 2)
  • Use bracket notation: a[]=value (not indexed a[0]=value)

Impact

Denial of Service via memory exhaustion. Affects applications using qs.parse() with user-controlled input and arrayLimit for protection.

Attack scenario:

  1. Attacker sends HTTP request: GET /api/search?filters[]=x&filters[]=x&...&filters[]=x (100,000+ times)
  2. Application parses with qs.parse(query, { arrayLimit: 100 })
  3. qs ignores limit, parses all 100,000 elements into array
  4. Server memory exhausted → application crashes or becomes unresponsive
  5. Service unavailable for all users

Real-world impact:

  • Single malicious request can crash server
  • No authentication required
  • Easy to automate and scale
  • Affects any endpoint parsing query strings with bracket notation

Suggested Fix

Add arrayLimit validation to the bracket notation handler. The code already calculates currentArrayLength at line 147-151, but it's not used in the bracket notation handler at line 159.

Current code (lib/parse.js:159-162):

if (root === '[]' && options.parseArrays) {
    obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
        ? []
        : utils.combine([], leaf);  // No arrayLimit check
}

Fixed code:

if (root === '[]' && options.parseArrays) {
    // Use currentArrayLength already calculated at line 147-151
    if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
        throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
    }
    
    // If limit exceeded and not throwing, convert to object (consistent with indexed notation behavior)
    if (currentArrayLength >= options.arrayLimit) {
        obj = options.plainObjects ? { __proto__: null } : {};
        obj[currentArrayLength] = leaf;
    } else {
        obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
            ? []
            : utils.combine([], leaf);
    }
}

This makes bracket notation behaviour consistent with indexed notation, enforcing arrayLimit and converting to object when limit is exceeded (per README documentation).


Release Notes

ljharb/qs (qs)

v6.14.1

Compare Source

  • [Fix] ensure arrayLength applies to [] notation as well
  • [Fix] parse: when a custom decoder returns null for a key, ignore that key
  • [Refactor] parse: extract key segment splitting helper
  • [meta] add threat model
  • [actions] add workflow permissions
  • [Tests] stringify: increase coverage
  • [Dev Deps] update eslint, @ljharb/eslint-config, npmignore, es-value-fixtures, for-each, object-inspect

v6.14.0

Compare Source

  • [New] parse: add throwOnParameterLimitExceeded option (#​517)
  • [Refactor] parse: use utils.combine more
  • [patch] parse: add explicit throwOnLimitExceeded default
  • [actions] use shared action; re-add finishers
  • [meta] Fix changelog formatting bug
  • [Deps] update side-channel
  • [Dev Deps] update es-value-fixtures, has-bigints, has-proto, has-symbols
  • [Tests] increase coverage

Configuration

📅 Schedule: Branch creation - "" (UTC), 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 label Jan 1, 2026
@safedep
Copy link

safedep bot commented Jan 1, 2026

SafeDep Report Summary

Green Malicious Packages Badge Green Vulnerable Packages Badge Green Risky License Badge

Package Details
Package Malware Vulnerability Risky License Report
icon call-bind-apply-helpers @ 1.0.2
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon call-bound @ 1.0.4
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon dunder-proto @ 1.0.1
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon es-define-property @ 1.0.1
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon es-object-atoms @ 1.1.1
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon get-intrinsic @ 1.3.0
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon get-proto @ 1.0.1
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon gopd @ 1.2.0
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon has-symbols @ 1.1.0
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon math-intrinsics @ 1.1.0
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon qs @ 6.14.1
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon side-channel @ 1.1.0
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon side-channel-list @ 1.0.0
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon side-channel-map @ 1.0.1
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗
icon side-channel-weakmap @ 1.0.2
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗

This report is generated by SafeDep Github App

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant