CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-2391

Death by a Thousand Commas: Deep Dive into CVE-2026-2391

Alon Barad
Alon Barad
Software Engineer

Feb 12, 2026·6 min read·160 visits

Executive Summary (TL;DR)

The `qs` library (used by Express.js) ignores `arrayLimit` when parsing comma-separated values (`?a=1,2,3...`). Attackers can trigger OOM crashes by sending massive comma strings. Fixed in 6.14.2.

A logic flaw in the popular Node.js `qs` library allows attackers to bypass array limits when the `comma` parsing option is enabled. By sending a crafted query string containing thousands of commas, an unauthenticated attacker can force the application to allocate massive arrays, leading to memory exhaustion and a Denial of Service (DoS). This vulnerability highlights the dangers of 'return early' patterns in input validation logic.

The Hook: Parsing is Hard

If you've ever written a Node.js web server, you've almost certainly used qs. It's the de facto standard for parsing query strings, sitting underneath heavyweights like Express.js. It turns the chaotic soup of URL parameters (?foo=bar&baz=qux) into nice, clean JavaScript objects. It handles deep nesting, arrays, and all the edge cases that the native querystring module ignores.

But here's the thing about parsing libraries: they are the frontline defense. They touch user input before your application logic even wakes up. If the parser is broken, your fancy authentication middleware doesn't matter. You are already dead.

CVE-2026-2391 targets a specific convenience feature in qs: Comma-Separated Values. Sometimes developers want ?ids=1,2,3 to automatically become ['1', '2', '3'] without forcing the client to send ?ids[]=1&ids[]=2.... To support this, qs offers the comma: true option. It sounds innocent enough, but as we're about to see, enabling this option essentially handed attackers a 'Skip Logic' card for security controls.

The Flaw: Logic Amnesia

The vulnerability isn't a complex buffer overflow or a heap grooming masterpiece. It's a classic case of Order of Operations failure. Developers often implement security limits—like arrayLimit—to prevent memory exhaustion. In qs, the default arrayLimit is 20. If you try to send 100 items, qs is supposed to stop parsing or convert the excess into an object index to save memory.

However, in lib/parse.js, the logic for handling commas was implemented before the limit checks were fully enforced. The code looked at the input string, saw a comma, and immediately thought, "I know what to do here! I'll split this string and return the result right now!"

> [!NOTE] > The Fatal Mistake: The code returned the result of val.split(',') immediately. It bypassed the subsequent code blocks responsible for checking if the resulting array size exceeded the configured limit.

This means that even if you configured qs to throw an error when limits are exceeded (throwOnLimitExceeded: true), the comma parser would happily generate an array of 1,000,000 items before the validator ever got a chance to object. It’s like a bouncer checking ID at the front door, but leaving the loading dock wide open for anyone carrying a box.

The Code: The Smoking Gun

Let's look at the diff. This is where the oversight becomes painful to read. The vulnerability lived in the parseValues function.

The Vulnerable Code (Simplified):

// lib/parse.js (Pre-patch)
var parseValues = function (str, options) {
    // ... setup ...
 
    // IF commas are enabled and present...
    if (options.comma && val.indexOf(',') > -1) {
        // ... SPLIT AND RETURN IMMEDIATELY
        return val.split(',');
    }
 
    // ... complex parsing logic and LIMIT CHECKS happen down here ...
};

See that return? That's the game over. The function exits before it ever reaches the code that says, "Hey, is this array too big?"

The Fix (Commit f6a7abf):

The maintainers fixed this by removing the early return and explicitly checking the length of the generated array against the arrayLimit.

// lib/parse.js (Patched)
if (options.comma && val.indexOf(',') > -1) {
    var values = val.split(',');
    // Explicitly check the limit on the split result
    if (values.length > options.arrayLimit) {
        if (options.throwOnLimitExceeded) {
            throw new RangeError('Array limit exceeded...');
        }
        // Or safely combine/truncate
        values = utils.combine([], values, options.arrayLimit, options.plainObjects);
    }
    return values;
}

The fix forces the comma-split array to undergo the same scrutiny as any other array structure.

The Exploit: DoS via Allocation

Exploiting this is trivially easy if you can find an endpoint where comma: true is enabled. You don't need special headers, you don't need to bypass a WAF (usually), and you don't need authentication.

The Attack Scenario:

  1. Recon: The attacker identifies a target using qs (common in Node.js apps). They fuzz parameters with commas (?q=a,b) to see if the server treats them as arrays.
  2. Weaponization: The attacker constructs a query string containing a single parameter with millions of commas.
  3. Execution: They send the request. The Node.js event loop blocks while String.prototype.split allocates a massive array of strings on the heap.

Proof of Concept:

const qs = require('qs');
 
// Target configuration
const options = {
    comma: true,
    arrayLimit: 5, // We expect this to stop us... but it won't.
    throwOnLimitExceeded: true
};
 
// The payload: 1 million commas
const attackPayload = 'data=' + 'a,'.repeat(1000000);
 
console.log("Attempting parse...");
try {
    const result = qs.parse(attackPayload, options);
    console.log(`Success! Array length: ${result.data.length}`);
    console.log("The limit of 5 was completely ignored.");
} catch (e) {
    console.log("Blocked:", e.message);
}

When run against a vulnerable version, this script outputs Array length: 1000001. The memory usage spikes instantly. If an attacker sends concurrent requests like this, the Node.js process will hit its memory limit (default ~1.5GB) and crash with FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory.

The Impact: Why It Matters

You might argue, "Who enables comma: true anyway?" It's less common than the default behavior, but it is frequently used in APIs that want to support compact filter lists (e.g., GET /users?ids=1,2,3).

The consequences are:

  • Availability Loss: A single attacker can crash the server (DoS). Since Node.js is often deployed with process managers (like PM2) that restart crashes, the attacker can put the server into a continuous crash loop, effectively taking it offline.
  • Resource Cost: For serverless environments (AWS Lambda, etc.), this causes massive CPU spikes and max memory usage, driving up the bill even if the function eventually times out.
  • Latency: Even if the server doesn't crash, the Garbage Collector (GC) will go into overdrive trying to clean up these massive string arrays, causing significant latency for legitimate users.

This is a classic Asymmetric Attack: It costs the attacker fractions of a penny to generate a string of commas, but it costs the defender significant CPU cycles and RAM to process it.

The Fix: Mitigation & Defense

The remediation is straightforward, but it requires action. This isn't a vulnerability that will magically go away.

Immediate Steps:

  1. Patch: Update qs to 6.14.2 or higher. Run npm audit fix or manually upgrade your package.json.
  2. Configuration Review: Search your codebase for comma: true. If you don't actually need comma-separated parsing, turn it off. The safest code is code that doesn't run.
  3. Input Validation: Regardless of the library fix, you should validate the length of input strings at the ingress point (e.g., Nginx, AWS WAF). Reject query strings that are unreasonably long (e.g., > 2KB) before they ever reach your Node.js application.

> [!TIP] > Developer Lesson: Never assume a library enforces its own constraints consistently across all features. When enabling "convenience" features (like fuzzy matching or comma parsing), always verify if the standard security limits still apply.

Official Patches

GitHubOfficial patch commit

Fix Analysis (1)

Technical Appendix

CVSS Score
6.3/ 10
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
EPSS Probability
0.05%
Top 85% most exploited

Affected Systems

Node.js applications using `qs`Express.js applications (if using `qs` with custom configuration)APIs parsing CSV-style query parameters

Affected Versions Detail

Product
Affected Versions
Fixed Version
qs
ljharb
<= 6.14.16.14.2
AttributeDetail
CWECWE-20 / CWE-770
CVSS v4.06.3 (Medium)
Attack VectorNetwork (Remote)
PrivilegesNone
ImpactDenial of Service (Memory Exhaustion)
EPSS Score0.00049 (~0.05%)

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1499Endpoint Denial of Service
Impact
CWE-770
Allocation of Resources Without Limits or Throttling

Improper Input Validation leading to Allocation of Resources Without Limits

Known Exploits & Detection

Internal ResearchPoC demonstrating memory spike with comma-separated values

Vulnerability Timeline

Fix committed to GitHub
2026-02-10
CVE and GHSA Published
2026-02-12

References & Sources

  • [1]GitHub Security Advisory
  • [2]NVD CVE-2026-2391

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 12 hours ago•CVE-2026-53359
8.8

CVE-2026-53359: Use-After-Free in Linux Kernel KVM Shadow MMU (Januscape)

Januscape (CVE-2026-53359) is a critical Use-After-Free vulnerability in the x86 Shadow MMU component of the Linux Kernel's KVM subsystem. A logic error in shadow page tracking permits unauthorized page reuse without validating architectural execution roles, leading to dangling pointers in reverse mapping (rmap) tracking entries during guest memory teardown.

Amit Schendel
Amit Schendel
60 views•5 min read
•about 13 hours ago•CVE-2026-48282
10.0

CVE-2026-48282: Unauthenticated Path Traversal and Arbitrary File Write in Adobe ColdFusion Remote Development Services

CVE-2026-48282 is a critical unauthenticated path traversal and arbitrary file write vulnerability in the Remote Development Services (RDS) component of Adobe ColdFusion. The vulnerability allows a remote, unauthenticated attacker to bypass directory boundaries and write arbitrary files, including CFML-based web shells, onto the host server. This flaw is actively exploited in the wild and enables full unauthenticated remote code execution under the privileges of the ColdFusion service account.

Alon Barad
Alon Barad
22 views•6 min read
•about 17 hours ago•GHSA-GQ4G-FPC9-VJFQ
2.3

GHSA-gq4g-fpc9-vjfq: Username Enumeration via Predictable Decoy Credentials in web-auth/webauthn-lib

An information disclosure vulnerability exists in the web-auth/webauthn-lib PHP library when using the default SimpleFakeCredentialGenerator without a configured secret. This allows unauthenticated remote attackers to determine if a username exists on the target application.

Alon Barad
Alon Barad
8 views•5 min read
•about 18 hours ago•GHSA-CWV4-H3J5-W3CF
3.7

GHSA-CWV4-H3J5-W3CF: Stored and Reflected Cross-Site Scripting in rama's Directory Listing Component

A Stored and Reflected Cross-Site Scripting (XSS) vulnerability was identified in the Rust web service library 'rama' prior to version 0.3.0-rc.1. When serving directories using DirectoryServeMode::HtmlFileList, the library improperly escapes directory names, filenames, and request path components before injecting them into dynamically generated HTML files. This allows attackers to execute malicious scripts inside user browser sessions.

Alon Barad
Alon Barad
7 views•7 min read
•about 19 hours ago•GHSA-Q855-8RH5-JFGQ
6.5

GHSA-Q855-8RH5-JFGQ: Missing Authentication and CSRF in ha-mcp bare root settings and policy routes

The ha-mcp add-on for Home Assistant exposes its settings and security policy routes without authentication at the bare root path of TCP port 9583. This exposure allows unauthorized adjacent network clients to reconfigure tools, alter policies, and bypass human-in-the-loop approval gates. The vulnerability has been addressed in development build 7.6.0.dev393 and subsequent releases by restricting access to root-mounted routes exclusively to the Supervisor Ingress IP.

Amit Schendel
Amit Schendel
6 views•8 min read
•about 19 hours ago•GHSA-F66Q-9RF6-8795
5.3

GHSA-f66q-9rf6-8795: WebAuthn Re-authentication Freshness Bypass in Flask-Security-Too

An authentication freshness bypass vulnerability exists in the WebAuthn re-authentication path of Flask-Security-Too versions 5.8.0 and 5.8.1. The flaw allows an authenticated attacker to elevate the freshness status of a victim session using their own WebAuthn credential, bypassing re-authentication constraints.

Amit Schendel
Amit Schendel
8 views•5 min read