CVE-2025-15284: When a Safety Limit Isn’t a Safety Limit — Breaking qs Array Parsing

CVE ID: CVE-2025-15284
Severity: HIGH
CVSS Score: 7.5
Impact: Availability (Denial of Service)

Exploitability Summary

  • Remotely exploitable over the network
  • No authentication required
  • No user interaction required
  • Low technical effort
  • Public proof-of-concept code available

This vulnerability allows attackers to crash or severely degrade Node.js applications by exploiting a flaw in how query string arrays are parsed. In many cases, a single crafted HTTP request is sufficient to trigger excessive memory usage and take the service offline.


What Is Going Wrong

The issue exists in the qs library, a widely used query string parser across the Node.js ecosystem. Developers frequently rely on its arrayLimit option as a defensive measure against abusive requests that attempt to send very large arrays.

The problem is that this protection is only partially enforced.

  • When query parameters use indexed array notation (e.g., a[0]=1&a[1]=2), the limit is correctly enforced.
  • When the same data is sent using bracket notation (e.g., a[]=1&a[]=2), the limit is silently ignored.

From the application’s point of view, everything appears secure. In reality, one entire parsing path operates with no size enforcement at all.


Why This Matters

Modern APIs frequently accept filters, tags, search options, and flags through query parameters. Array-based inputs are extremely common and often exposed on public endpoints.

Developers reasonably assume that configuring something like:

qs.parse(query, { arrayLimit: 100 })

means that no request can create arrays larger than 100 elements.

With this vulnerability, that assumption does not hold. An attacker can submit tens of thousands of array elements in a single request, forcing the server to allocate large in-memory structures before authentication, validation, or business logic is reached.


Root Cause Explained Simply

Internally, the parser follows two different code paths depending on how arrays are expressed in the URL.

Indexed Arrays (a[0], a[1])

  • Explicit numeric index
  • Checked against arrayLimit
  • Safely rejected once the limit is exceeded

Bracket Arrays (a[])

  • No index provided
  • Routed through a separate parsing branch
  • Elements appended directly to the array
  • No limit check performed at any stage

This inconsistency turns bracket notation into an unbounded memory sink.


How an Attack Unfolds

  1. An attacker identifies an endpoint that accepts query parameters
  2. They generate a request containing thousands of param[]=value entries
  3. The server receives the request and immediately begins parsing
  4. qs allocates a new array element for each occurrence
  5. Memory usage grows rapidly
  6. The Node.js process slows, freezes, or crashes
  7. The service becomes unavailable for all users

This entire chain can occur in milliseconds.


Realistic Exploitation Scenarios

Scenario 1: Public Search API

A product search endpoint accepts category filters via query parameters.
The backend configures arrayLimit to prevent abuse.

An attacker sends a request containing tens of thousands of category[]=x parameters.
Despite the configured limit, the application parses all entries, exhausts memory, and crashes.

Result: Complete API outage.


Scenario 2: Internal Dashboard Route

An internal dashboard accepts notification IDs through query parameters.
The route is unauthenticated because it is considered low risk.

A malicious request floods the parser with bracket arrays, freezing the process.

Result: Internal tools become unavailable and operational workflows are disrupted.


Scenario 3: Automated Flooding

Attackers deploy bots that repeatedly send oversized array requests to multiple endpoints.

Each request appears syntactically valid and often bypasses traditional rate limiting because it is not high-volume traffic—just extremely heavy per request.

Result: Sustained denial of service with minimal effort.


Proof That the Limit Is Bypassed

Even with very small configured limits, bracket notation ignores enforcement entirely.

  • Configured array limit: 5
  • Actual parsed array size: 6+

With larger payloads, memory usage increases linearly, making this an effective resource-exhaustion attack.


How to Detect Exploitation Attempts

Network-Level Indicators

  • Extremely long query strings
  • Repeated []= patterns
  • Hundreds or thousands of identical parameter names
  • Requests dominated almost entirely by array parameters

Legitimate clients rarely send more than a few dozen array values in a single request.


Application-Level Symptoms

  • Sudden memory spikes immediately after request receipt
  • Increased garbage collection activity
  • Slow request handling before application logic executes
  • Node.js heap exhaustion errors
  • Unexpected process restarts or crashes

Log Evidence to Watch For

Web Server Logs

  • Requests with unusually large query strings
  • Repeated failures on endpoints that typically succeed

Application Logs

  • “JavaScript heap out of memory”
  • “Ineffective mark-compacts near heap limit”
  • Parsing timeouts or unexplained crashes

MITRE ATT&CK Alignment

  • Tactic: Impact
  • Technique: Endpoint Denial of Service (T1499)
  • Sub-Technique: Application Exhaustion Flood (T1499.003)

This vulnerability enables attackers to exhaust application resources by exploiting a weakness in application-layer parsing logic.


Remediation Guidance

Official Fix (Strongly Recommended)

Upgrade the qs library to version 6.14.1 or later.

The patch ensures that both indexed and bracket array notation respect the configured arrayLimit, fully closing the bypass.

Official Patch Source:
https://github.com/ljharb/qs/releases/tag/v6.14.1


Temporary Mitigations (If Immediate Patching Is Not Possible)

  • Enforce strict maximum query string length at the web server or gateway
  • Reject requests with excessive repeated parameters
  • Disable array parsing entirely if it is not required
  • Add middleware to count bracket-style parameters before parsing

These measures can reduce exposure but do not replace proper patching.


Aegiron

Backed by 11+ years in cybersecurity and incident response, we decode the latest threats shaping today’s digital battlefield. This blog cuts through the noise with clear insights on vulnerabilities, emerging exploits, and the cyber news defenders can’t afford to miss.