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

CVE-2026-102278: Stack-Based Denial of Service via Uncontrolled Recursion in brace-expansion

Amit Schendel
Amit Schendel
Senior Security Researcher

Sep 30, 2026·7 min read·4 visits

Executive Summary (TL;DR)

Uncontrolled recursion in nested brace groups allows unauthenticated attackers to crash the Node.js process via a stack overflow using compact (~6KB) inputs.

A stack-based Denial of Service (DoS) vulnerability via uncontrolled recursion in the brace-expansion library prior to versions 1.1.20, 2.1.6, 3.0.8, and 5.0.11 allows unauthenticated remote attackers to trigger native stack exhaustion, terminating the Node.js process via a crafted payload containing deeply nested brace groups.

Vulnerability Overview

The brace-expansion npm package is a widely used utility designed to resolve shell-like brace patterns into expanded string arrays. It is commonly integrated into toolchains, file-matching utilities, and security-critical path parsing systems such as the minimatch and glob libraries. Because these utilities often ingest user-provided input to locate resources or map system actions, the expansion parser forms an important security boundary for incoming input strings.

This vulnerability belongs to the class of Uncontrolled Recursion (CWE-674) leading to Uncontrolled Resource Consumption (CWE-400). When the library is supplied with deeply nested brace groups, the internal parsing function executes recursively for each level of nesting. Without structural limits on recursion depth, this execution pattern exhausts the allocated call stack of the underlying runtime engine.

The resulting impact is a severe, process-terminating Denial of Service (DoS). Because Node.js operates on a single-threaded event loop, an unhandled stack overflow exception terminates the application process abruptly. In environments lacking automated process restoration, this completely disables the application's availability to all users.

Root Cause Analysis

To resolve shell-like brace patterns (such as a{b,c}d into abd and acd), the brace-expansion library evaluates individual structural components recursively. A prior vulnerability, CVE-2026-14257, was mitigated by converting tail-parsing recursion into an iterative loop. This adjustment protected the library against chained sequences of expansion groups (such as a{b,c}d{e,f}...), ensuring that sequentially parsed blocks did not consume call stack frames.

However, the previous mitigation left nested brace groups completely unconstrained. The internal expansion engine relies on the function expand_ to process subdivisions of nesting. Uncontrolled recursion occurs in two distinct parsing conditions:

  1. Comma-Member Sets: In structures containing alternative execution paths within comma-separated segments (such as {a,{b,c}}), the parser recursively expands the internal structures before mapping the parent sequence.

  2. Single-Part Set Wrapping: In structures where a set consists of a single part requiring subsequent re-wrapping (such as x{{a,b}}y mapping to x{a}y and x{b}y), the code initiates a recursion pass on the inner content.

The V8 JavaScript engine enforces a hard limit on the native call stack size to prevent runaway memory consumption. If an untrusted string containing several thousand nested brackets is passed to the parser, the continuous allocation of activation records exceeds this stack frame ceiling. The environment throws a RangeError: Maximum call stack size exceeded exception. Because the exception is generated within the native engine loop of the library, applications rarely wrap these utilities in exception handling blocks, leading to immediate process termination.

Code Analysis

To understand the precise vulnerability and its mitigation, we analyze the changes introduced across the package branches. The patch implements a recursion-tracking mechanism by passing and incrementing a depth variable through the call tree.

The vulnerable code path did not enforce any structural depth tracking. In the TypeScript implementation, the entry-point function invoked the parser with hardcoded execution parameters:

// Vulnerable invocation path
return expand_(escapeBraces(str), max, maxLength, true).map(
  unescapeBraces,
)

The modified code introduces a default safety constant EXPANSION_MAX_DEPTH = 1000 and configures the main execution path to pass a starting depth of 0 while exposing maxDepth to users:

// Patched entry-point configuration
export const EXPANSION_MAX_DEPTH = 1_000
 
export function expand(str: string, options: BraceExpansionOptions = {}) {
  // ...
  const {
    max = EXPANSION_MAX,
    maxLength = EXPANSION_MAX_LENGTH,
    maxDepth = EXPANSION_MAX_DEPTH,
  } = options
 
  return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, true).map(
    unescapeBraces,
  )
}

Inside the recursive expand_ function, a strict guard is positioned at the very top of the function body. If the tracking parameter depth exceeds the configured maxDepth, the recursion terminates early and returns the string literally:

function expand_(
  str: string,
  max: number,
  maxLength: number,
  maxDepth: number,
  depth: number,
  isTop: boolean,
): string[] {
  // Guard clause against deep nesting exhaustion
  if (depth > maxDepth) {
    return [str]
  }
  // ...

The recursive calls for both comma-member processing and single-part re-wrapping are modified to increment the depth parameter:

// Single-part set wrapping recursion path
n = expand_(n[0], max, maxLength, maxDepth, depth + 1, false).map(
  embrace,
)
 
// ...
 
// Comma-member expansion recursion path
const expanded = expand_(
  n[j] as string,
  max,
  maxLength,
  maxDepth,
  depth + 1,
  false,
)

By transitioning the return type to a literal string array once the maximum depth is violated, the function avoids raising an exception entirely. This ensures that the function remains total (non-throwing) and executes deterministically regardless of input complexity.

Exploitation Methodology

Exploiting this vulnerability does not require authentication or specific configuration parameters. The attacker must only identify an application endpoint that accepts a string and passes it into a component utilizing brace-expansion. Because the library is a common dependency of glob-matching libraries, applications that accept search queries or route definitions are vulnerable.

Because the execution limiters introduced in prior patches only restricted total string length (EXPANSION_MAX_LENGTH) and total output item count (EXPANSION_MAX), they are ineffective at preventing this crash. A payload containing nested braces produces a final output of negligible size and length, bypassing both checks. For instance, {{{...a,b...}}} results in only a single expansion array with two strings, but the depth of the tree is what triggers the crash.

Two specific payload formats can be leveraged to trigger process termination depending on the targeted code-level handling:

// Payload A: Single-Part Nested Set Shape (~6KB)
const expand = require('brace-expansion');
const payload = '{'.repeat(10000) + 'a,b' + '}'.repeat(10000);
expand(payload); // Instantly triggers RangeError and crashes Node.js
// Payload B: Comma-Member Nested Set Shape (~15.6KB)
const expand = require('brace-expansion');
const payload = '{a,'.repeat(10000) + 'z' + '}'.repeat(10000);
expand(payload); // Crashes the process via native call stack exhaustion

These payloads are highly compact, meaning standard HTTP request body limiters (which typically allow up to 100KB or 1MB) will fail to block them. This disparity allows attackers to exhaust the host's capabilities with minimal network overhead.

Impact Assessment

The primary security impact of CVE-2026-102278 is a complete and low-cost Denial of Service (DoS) of the targeted Node.js process. In single-threaded JavaScript environments, an unhandled exception of this nature stops the entire event loop, dropping all active connections and preventing the server from handling subsequent requests.

The CVSS v3.1 base score for this vulnerability is assessed at 7.5 (High), with the vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H. The severity is elevated because the attack can be launched remotely without credentials, is simple to execute, requires no user interaction, and results in a total loss of availability for the component.

In containerized or cloud-native environments, container runtimes may automatically restart the crashed process. However, if an attacker repeatedly sends the payload, the rapid loop of crashes and restarts—often called a crash-loop state—will quickly exhaust container resource limits, raise orchestration alerts, and degrade the performance of adjacent services sharing the same node.

Remediation and Mitigation

The definitive resolution for this vulnerability is upgrading the brace-expansion library to a patched release. Maintainers have released fixes across all major version branches. Organizations should audit their dependency trees and enforce the following upgrade paths:

  • In projects using 1.x branches, upgrade to 1.1.20 or higher.
  • In projects using 2.x branches, upgrade to 2.1.6 or higher.
  • In projects using 3.x branches, upgrade to 3.0.8 or higher.
  • In projects using 4.x or 5.x branches, upgrade to 5.0.11 or higher.

If upgrading is not immediately possible, applications should implement input-validation middleware to inspect string inputs for repeated brace patterns. Rejecting inputs that exceed a specific number of nested braces (for example, preventing sequences of more than 10 consecutive { or } characters) effectively mitigates the exploit path. Additionally, configuring a process manager such as pm2 or using clustered Node.js configurations can maintain service availability by automatically spawning worker processes when an unhandled crash occurs.

Official Patches

juliangruberNesting depth enforcement commit inside TypeScript implementation.
juliangruberNesting depth enforcement commit inside vanilla JS ESM module.
juliangruberNesting depth enforcement commit inside CommonJS legacy module.

Fix Analysis (3)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.35%
Top 74% most exploited

Affected Systems

Node.js applications processing untrusted shell-like patterns or glob vectors via brace-expansion.Libraries utilizing brace-expansion transitively, such as older versions of minimatch or glob parsers.

Affected Versions Detail

Product
Affected Versions
Fixed Version
brace-expansion
juliangruber
< 1.1.201.1.20
brace-expansion
juliangruber
>= 2.0.0, < 2.1.62.1.6
brace-expansion
juliangruber
>= 3.0.0, < 3.0.83.0.8
brace-expansion
juliangruber
>= 4.0.0, < 5.0.115.0.11
AttributeDetail
CWE IDCWE-674
Attack VectorNetwork (Unauthenticated)
CVSS7.5 (High)
EPSS0.0035 (26th percentile)
ImpactDenial of Service (Process Termination)
Exploit StatusProof-of-Concept
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-674
Uncontrolled Recursion

The software directs the code to recurse, but it does not limit or control the number of recursive loops, leading to stack exhaustion.

Known Exploits & Detection

GitHub AdvisorySecurity advisory details containing vulnerability mechanics and reproduction methods.

Vulnerability Timeline

Technical fix commits designed, implemented, and merged by maintainer Julian Gruber on repository branches.
2026-09-14
Security advisory published and CVE-2026-102278 assigned. Patched packages released.
2026-09-28
EPSS scores populated and threat models analyzed. No active exploitation identified.
2026-09-29

References & Sources

  • [1]Official GitHub Advisory GHSA-qhr7-859c-m2p7
  • [2]NVD CVE-2026-102278 Reference

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

•7 minutes ago•CVE-2026-102276
7.5

CVE-2026-102276: Denial of Service via Uncontrolled Recursion and Argument-List Exhaustion in brace-expansion

CVE-2026-102276 is a high-severity Denial of Service (DoS) vulnerability impacting the 'brace-expansion' library, a popular Node.js utility designed to expand brace patterns into combinatorial lists. Due to uncontrolled recursion and argument-list stack exhaustion within the internal parseCommaParts function, remote attackers can trigger an unhandled RangeError that abruptly terminates the Node.js process.

Alon Barad
Alon Barad
1 views•7 min read
•about 2 hours ago•CVE-2026-102277
5.3

CVE-2026-102277: Denial of Service via Quadratic Algorithmic Complexity in brace-expansion

An uncontrolled resource consumption vulnerability exists in the brace-expansion JavaScript library. Due to an algorithmic flaw in parsing a legacy Bash-compatibility quirk involving {a},b}-shaped expansion structures, untrusted inputs containing many trailing closing braces trigger successive full-input rescans. This behavior yields quadratic CPU time complexity and high memory overhead, allowing remote, unauthenticated attackers to cause a Denial of Service (DoS) by blocking the single-threaded Node.js event loop.

Amit Schendel
Amit Schendel
5 views•7 min read
•about 3 hours ago•CVE-2026-17495
5.9

CVE-2026-17495: Path Traversal via Type Confusion in Moment.js Dynamic Locale Loading

Moment.js versions 2.29.2 through 2.30.1 are vulnerable to a Path Traversal flaw (CWE-27) on server-side Node.js environments when dynamic locales are configured. The vulnerability stems from an object-coercion bypass in the locale-name sanitization routine, which assumes incoming variables are string primitives. An attacker can pass a structured object with custom 'match' and 'toString' properties to bypass regex-based directory checks, leading to arbitrary file loading via Node's internal 'require()' call.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 5 hours ago•CVE-2026-101911
6.3

CVE-2026-101911: Denial of Service via Uncontrolled Resource Consumption in ip-address Library

A denial-of-service vulnerability exists in the ip-address npm package prior to version 10.7.1. The library fails to limit the length of input strings parsed by the Address4 and Address6 constructors. When parsing highly malformed addresses, the diagnostic parser runs a synchronous regular expression search-and-replace that generates descriptive HTML error messages. Passing an excessively long string containing invalid characters causes severe memory amplification and CPU starvation, resulting in a thread hang or process crash in Node.js applications.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 6 hours ago•CVE-2026-101912
6.3

CVE-2026-101912: Cross-Family IP Address Subnet Containment Logic Bypass in ip-address Library

The ip-address library is vulnerable to a logical bypass in its subnet containment methods. The functions isInSubnet() and isHostInSubnet() do not verify that compared addresses belong to the same IP family before performing masking checks. Under specific circumstances, an IPv6 address can share leading bit patterns with an IPv4 subnet, causing the containment check to evaluate as true. This allows attackers to bypass access control lists, firewalls, and server-side request forgery protection layers in applications relying on the library.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 7 hours ago•CVE-2026-101894
9.1

CVE-2026-101894: Arbitrary File Read/Write via Symbolic Link Chaining in @xhmikosr/decompress

CVE-2026-101894 is a critical path traversal vulnerability in @xhmikosr/decompress before versions 10.2.2 and 11.1.4, stemming from an incomplete hardening bypass of CVE-2026-53486 where static lexical containment checks fail to detect kernel-level resolution of crafted symlink chains, allowing arbitrary local file modification and execution.

Amit Schendel
Amit Schendel
5 views•7 min read