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.14.06.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

Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, 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 requested a review from a team as a code owner January 1, 2026 21:08
@renovate renovate bot requested a review from alisherry January 1, 2026 21:08
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 1, 2026

Greptile Summary

This PR patches CVE-2025-15284, a DoS vulnerability in the qs library. The vulnerability allows attackers to bypass the arrayLimit option using bracket notation (a[]=1&a[]=2), enabling memory exhaustion attacks.

Key Points:

  • Updates qs from 6.14.0 to 6.14.1 (security patch)
  • The codebase uses qs.stringify() only, not qs.parse(), so it is not vulnerable to this CVE
  • Usage in src/user-management/user-management.ts:163 and src/sso/sso.ts:31 only serializes objects to query strings
  • The CVE affects qs.parse() with user-controlled input when using arrayLimit for DoS protection
  • No code changes required beyond dependency update

Confidence Score: 5/5

  • This PR is safe to merge with no risk
  • Score reflects that this is a straightforward security patch for a dependency. The codebase only uses qs.stringify() for creating query strings, not qs.parse() which is the vulnerable function. The CVE does not impact this repository's usage pattern. The update includes proper version bump and integrity hashes.
  • No files require special attention

Important Files Changed

Filename Overview
package.json Updated qs dependency from 6.14.0 to 6.14.1 to patch CVE-2025-15284 (DoS vulnerability)
package-lock.json Lockfile updated to reflect qs 6.14.1 with correct integrity hash and license metadata

Sequence Diagram

sequenceDiagram
    participant Dev as Developer/Renovate Bot
    participant Repo as workos-node Repository
    participant NPM as NPM Registry
    participant QS as qs Library (6.14.1)
    
    Note over Dev,QS: Security Update: CVE-2025-15284 Patch
    
    Dev->>Repo: Update package.json (qs: 6.14.0 → 6.14.1)
    Dev->>Repo: Update package-lock.json with new hash
    
    Note over Repo: Build/Install Phase
    Repo->>NPM: Request [email protected]
    NPM->>QS: Download patched version
    QS-->>Repo: Install with arrayLimit fix
    
    Note over Repo,QS: Runtime Usage (Not Vulnerable)
    
    rect rgb(200, 255, 200)
        Note over Repo: user-management.ts:163
        Repo->>QS: qs.stringify(options) - Safe
        QS-->>Repo: Query string created
        
        Note over Repo: sso.ts:31
        Repo->>QS: qs.stringify(options) - Safe
        QS-->>Repo: Query string created
    end
    
    Note over Repo,QS: CVE affects qs.parse() only<br/>This codebase uses qs.stringify() only
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, no comments

Edit Code Review Agent Settings | Greptile

@renovate renovate bot changed the title fix(deps): update dependency qs to v6.14.1 [security] fix(deps): update dependency qs to v6.14.1 [security] - autoclosed Jan 2, 2026
@renovate renovate bot closed this Jan 2, 2026
@renovate renovate bot deleted the renovate/npm-qs-vulnerability branch January 2, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant