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-13149

CVE-2026-13149: Algorithmic Complexity Denial of Service in brace-expansion

Alon Barad
Alon Barad
Software Engineer

Jul 20, 2026·6 min read·14 visits

Executive Summary (TL;DR)

An algorithmic complexity flaw in brace-expansion prior to version 5.0.7 allows unauthenticated remote attackers to trigger an exponential-time O(2^n) execution path using short, crafted strings, causing complete thread starvation and Denial of Service in Node.js applications.

CVE-2026-13149 is a highly severe algorithmic complexity vulnerability in the brace-expansion Node.js library prior to version 5.0.7. When parsing consecutive non-expanding brace groups, the library exhibits exponential-time complexity, leading to process-level Denial of Service in single-threaded runtimes.

Vulnerability Overview

The NPM library brace-expansion is a foundational package responsible for resolving shell-like brace expansions such as file{1..3}.txt into discrete arrays of strings. Because it is transitively consumed by highly popular path-matching libraries like minimatch and glob, its attack surface extends to any downstream application that evaluates user-controlled input. Common exposure points include file upload endpoints, custom query engines, search criteria forms, and request router rules.

The core parsing engine within brace-expansion handles brackets and sequences recursively. However, when processing specific patterns of consecutive non-expanding brace groups, the library suffers from a classic Algorithmic Complexity flaw (CWE-407). This algorithmic inefficiency allows an attacker to manipulate the processing engine into performing exponential-time operations relative to the input length.

In Node.js, the execution of JavaScript code is bound to a single-threaded event loop. If a CPU-bound function blocks the event loop, all concurrent operations are starved, causing the service to become unresponsive. An unauthenticated attacker can exploit this behavior by submitting a payload of less than 100 bytes, which halts the application thread and causes an application-wide Denial of Service.

Root Cause Analysis

The root cause of CVE-2026-13149 lies in the main expansion routine expand_. When parsing a target string, the engine performs an unconditional, eager evaluation of the suffix or remaining part of the string (m.post) before validating whether the current brace group should actually expand.

When a non-expanding brace group like a{} is encountered, the parser reaches a rewrite rule that handles patterns matching {a},b}. The engine is designed to handle non-expanding groups by escaping the closing brace, rewriting the string, and starting the expansion process over again via a recursive call: return expand_(str, max, true).

This architecture creates a double-execution branch. The recursive evaluation of m.post is computed during the initialization of the current call frame, and then completely discarded when the rewrite logic is triggered and restarts the calculation on the rewritten string. As a result, each successive non-expanding group forces the engine to branch twice over the trailing substring.

This behavior yields an exponential execution recurrence relation:

$$T(n) = 2 \cdot T(n-1) + O(1)$$

Where $n$ represents the count of consecutive non-expanding brace groups. A string containing 30 non-expanding groups demands over one billion redundant calculations, completely exhausting the CPU resources allocated to the process thread.

Code Analysis

To understand the mechanics of the flaw, compare the vulnerable execution path with the patched implementation in version 5.0.7. The vulnerable parser processed the suffix immediately upon parsing the balanced group:

function expand_(str, max, isTop) {
  var expansions = [];
  var m = balanced('{', '}', str);
  if (!m) return [str];
 
  // VULNERABLE: "post" is recursively evaluated unconditionally here
  var pre = m.pre;
  var post = m.post.length ? expand_(m.post, max, false) : [''];
 
  if (/\$$/.test(m.pre)) { 
    // dollar prefix logic
  } else {
    // ... sequence check ...
    if (!isSequence && !isOptions) {
      if (m.post.match(/,(?!,).*\}/)) {
        str = m.pre + '{' + m.body + escClose + m.post;
        // VULNERABLE: Recursion discards the already computed "post" variable
        return expand_(str, max, true); 
      }
      return [str];
    }
  }
}

The patch addresses this structural defect in two ways: it defers the suffix expansion until after validation, and it replaces recursion with an iterative loop. This eliminates both the exponential branching and the risk of call stack exhaustion:

function expand_(str, max, isTop) {
  const expansions = [];
 
  // FIX: Loop instead of recursively calling expand_ to avoid stack exhaustion
  for (;;) {
    const m = balanced('{', '}', str);
    if (!m) return [str];
    const pre = m.pre;
 
    if (/\$$/.test(m.pre)) {
      // Suffix is evaluated here only if required
      const post = m.post.length ? expand_(m.post, max, false) : [''];
      // ... execution continue ...
    }
 
    const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
    const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
    const isSequence = isNumericSequence || isAlphaSequence;
    const isOptions = m.body.indexOf(',') >= 0;
 
    if (!isSequence && !isOptions) {
      if (m.post.match(/,(?!,).*\}/)) {
        str = m.pre + '{' + m.body + escClose + m.post;
        isTop = true;
        // FIX: Utilize loop continuation rather than creating a new call frame
        continue;
      }
      return [str];
    }
 
    // FIX: Suffix computation is deferred until the group is confirmed as expanding
    const post = m.post.length ? expand_(m.post, max, false) : [''];
    // ... standard expansion paths ...
  }
}

Exploitation Methodology

Exploiting this vulnerability does not require complex payloads or network states. Because the execution complexity scales exponentially, an attacker can trigger the CPU exhaustion sequence using a short string containing consecutive empty or non-expanding braces.

An example of a functional payload is:

a{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}

This payload consists of 30 non-expanding brace groups and is only 90 bytes long. A Python-based script or a raw HTTP request sending this payload to an exposed API parameter causes immediate thread block:

const { expand } = require('brace-expansion');
// A 90-byte input halts the main application thread for ~120 seconds
expand('a{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}');

When a Node.js process receives this payload, the event loop stops processing incoming HTTP connections, database query callbacks, and network packets. Downstream clients experience timeouts, and routing proxies (e.g., Nginx or HAProxy) return HTTP 504 Gateway Timeout or HTTP 502 Bad Gateway responses.

Impact Assessment

The overall impact of CVE-2026-13149 is scored as High because it results in process-level Denial of Service. In environments where multi-threading or clustering is not configured, a single attack payload disables the entire application interface.

While CVSS v3.1 evaluated the availability impact as Low due to traditional scoping rules, the CVSS v4.0 framework assesses it with a base score of 7.7 and a High Availability rating (VA:H). This update reflects the real-world operational impact of event-loop blockages within Node.js microservices.

Because the payload size is so small, an attacker can sustain a total Denial of Service with minimal bandwidth. They only need to transmit one packet every few minutes per worker process, which bypasses traditional network-layer rate limiting systems.

Remediation and Mitigation

The primary mitigation is updating the brace-expansion library to a patched release. Ensure that transitive dependencies are updated across all project lockfiles.

If you are using Node.js, you can identify vulnerable packages using the dependency analyzer:

npm ls brace-expansion

If the library is included as a transitive dependency of packages such as minimatch or glob, use the package overrides feature in your package.json to enforce the safe versions:

"resolutions": {
  "brace-expansion": "^5.0.7"
}

For systems where immediate updates cannot be deployed, you can use a validation filter to reject inputs containing sequential brace patterns before they reach the expansion engine:

const dangerousPattern = /(?:\{[^,.]*\}\s*,?\s*){4,}/;
function validateInput(input) {
  if (dangerousPattern.test(input)) {
    throw new Error('Invalid input payload detected');
  }
  return true;
}

Official Patches

Julian GruberV5.x Branch Fix Commit
Julian GruberV2.x Branch Backport Commit
Julian GruberV1.x Branch Backport Commit

Fix Analysis (3)

Technical Appendix

CVSS Score
7.7/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:P/S:N/AU:Y/R:U/V:D/RE:M/U:Amber
EPSS Probability
0.36%
Top 72% most exploited

Affected Systems

Node.js applications running brace-expansion <= 1.1.15Node.js applications running brace-expansion versions 2.0.0 through 2.1.1Node.js applications running brace-expansion versions 3.0.0 through 5.0.6Downstream packages consuming vulnerable versions of minimatch or glob

Affected Versions Detail

Product
Affected Versions
Fixed Version
brace-expansion
Julian Gruber
< 1.1.161.1.16
brace-expansion
Julian Gruber
>= 2.0.0 < 2.1.22.1.2
brace-expansion
Julian Gruber
>= 3.0.0 <= 5.0.65.0.7
AttributeDetail
CWE IDCWE-407 (Inefficient Algorithmic Complexity)
Attack VectorNetwork (AV:N)
CVSS v4.07.7 (High)
EPSS Score0.00361
ImpactDenial of Service (Thread Starvation)
Exploit StatusProof of Concept Available
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-407
Inefficient Algorithmic Complexity

The software uses an algorithm with an inefficient complexity, allowing an attacker to cause excessive consumption of CPU resources.

Known Exploits & Detection

GitHub Security AdvisoryOfficial advisory with detailed reproduction script and vulnerability analysis.

Vulnerability Timeline

Original patch implemented and merged into the v5.x branch by Julian Gruber.
2026-06-29
CVE-2026-13149 published in the NVD and CVE databases.
2026-06-30
Backports for production branches (v1.x and v2.x) merged. Patched versions 1.1.16 and 2.1.2 released.
2026-07-08
Full technical details and Proof of Concept published in public advisory GHSA-3jxr-9vmj-r5cp.
2026-07-20

References & Sources

  • [1]GitHub Security Advisory GHSA-3jxr-9vmj-r5cp
  • [2]NVD CVE-2026-13149 Record
  • [3]CVE.org CVE-2026-13149 Record
  • [4]NPM brace-expansion Package Homepage
  • [5]Upstream Git Repository

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

•4 minutes ago•CVE-2026-59197
8.2

CVE-2026-59197: Heap Out-of-Bounds Write and Division-by-Zero in Pillow libImaging

A heap out-of-bounds write vulnerability exists in Pillow prior to version 12.3.0 due to an integer overflow during image expansion calculations. The subsequent patch introduced a division-by-zero regression causing denial of service.

Alon Barad
Alon Barad
0 views•3 min read
•about 1 hour ago•CVE-2026-59198
6.5

CVE-2026-59198: Heap Out-of-Bounds Read in Pillow TGA RLE Encoder

CVE-2026-59198 is a high-severity heap out-of-bounds read vulnerability in Pillow, the Python imaging library, affecting versions from 5.2.0 up to 12.3.0. The vulnerability occurs in the TGA RLE compression path due to a calculation mismatch between the allocated packed 1-bit row buffer and the byte-level pixel stride assumption in the C-level encoder. This mismatch allows an attacker to leak up to approximately 57 KB of adjacent process heap memory directly into generated TGA image files.

Alon Barad
Alon Barad
1 views•8 min read
•about 2 hours ago•CVE-2026-59199
7.5

CVE-2026-59199: Signed 32-Bit Integer Overflow and Heap Backward Underwrite in Pillow

A critical signed 32-bit integer overflow vulnerability was identified in Pillow (Python Imaging Library) versions prior to 12.3.0. The vulnerability resides within the native C extension library (libImaging) during coordinate and bounding box calculations in functions like ImagingPaste and ImagingFill2. Exploitation can bypass bounds and clipping safety checks, leading to a controlled heap backward underwrite and application crash.

Alon Barad
Alon Barad
4 views•6 min read
•about 3 hours ago•CVE-2026-59200
7.5

CVE-2026-59200: Remote Denial of Service via PDF Decompression Bomb in Pillow

CVE-2026-59200 is a high-severity uncontrolled resource consumption vulnerability in the Pillow Python Imaging Library. The flaw resides in the PDF stream decoder, allowing remote, unauthenticated attackers to trigger host out-of-memory crashes by submitting malicious PDF decompression bombs.

Alon Barad
Alon Barad
4 views•5 min read
•about 4 hours ago•CVE-2026-59203
5.3

CVE-2026-59203: Denial of Service via Infinite Loop in Pillow EPS Image Parser

A denial-of-service (DoS) vulnerability in Pillow (Python Imaging Library) versions 12.0.0 through 12.2.0 allows unauthenticated remote attackers to trigger 100% CPU utilization and hang the processing thread. The issue occurs within the Encapsulated PostScript (EPS) image parser (PIL/EpsImagePlugin.py) due to missing validation on the byte count parsed from %%BeginBinary: comments, allowing negative values to cause an infinite backward stream seek loop. This formatting-level state-looping issue occurs during the initial format sniffing phase inside Image.open() and does not require the system Ghostscript interpreter to be executed or present. It is resolved in version 12.3.0.

Amit Schendel
Amit Schendel
4 views•6 min read
•about 5 hours ago•CVE-2026-59204
7.5

CVE-2026-59204: Denial of Service via Memory Exhaustion in Pillow JPEG2000 Decoder

A Denial of Service vulnerability exists in the JPEG2000 decoder of Pillow (versions 8.2.0 to 12.2.0) due to memory allocation state accumulation across tiles, leading to rapid process termination.

Amit Schendel
Amit Schendel
8 views•7 min read