Back to Blog
high SEVERITY6 min read

How Denial of Service via unbounded intermediate arrays happens in Node.js dependencies and how to fix it

A high-severity Denial of Service vulnerability (CVE-2026-69152) was discovered in the `brace-expansion` npm package, where crafted input could generate unbounded intermediate arrays that exhaust system memory. This bypasses the earlier CVE-2026-14257 mitigation. The fix upgrades `brace-expansion` from version 1.1.12 (and 2.0.2) to patched versions 1.1.18 across the dependency tree in the `exia-invasion` project.

O
By Orbis AppSec
Published August 16, 2026Reviewed August 16, 2026

Answer Summary

CVE-2026-69152 is a high-severity Denial of Service (DoS) vulnerability in the Node.js `brace-expansion` package (CWE-400) where specially crafted brace patterns generate unbounded intermediate arrays, bypassing the earlier CVE-2026-14257 fix. It affects versions prior to 1.1.18, 2.1.4, 3.0.6, and 5.0.9. The fix is to upgrade `brace-expansion` to a patched version that enforces bounds on intermediate array growth during expansion.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade brace-expansion to 1.1.18 (or 2.1.4, 3.0.6, 5.0.9) which enforces intermediate array bounds
riskApplication crash or unresponsiveness from memory exhaustion when processing crafted brace patterns
languageJavaScript (Node.js)
root causebrace-expansion generates unbounded intermediate arrays during expansion, bypassing prior size limits
vulnerabilityDenial of Service (DoS) via unbounded intermediate arrays

Introduction

In the exia-invasion project, a high-severity Denial of Service vulnerability was identified in the package-lock.json dependency tree. The brace-expansion package at version 1.1.12—used transitively through minimatch and readdir-glob—contained a flaw that allowed crafted brace patterns to generate unbounded intermediate arrays, exhausting system memory and crashing the application.

What makes CVE-2026-69152 particularly dangerous is that it bypasses the earlier CVE-2026-14257 mitigation. The prior fix added limits to final expansion output, but the new vulnerability exploits the intermediate expansion steps where arrays grow without bounds before any size check is applied. This means projects that believed they were patched against brace-expansion DoS attacks remained vulnerable.

The vulnerability was present in two locations within exia-invasion/package-lock.json: the top-level brace-expansion at version 1.1.12 and a nested instance under readdir-glob/node_modules/brace-expansion at version 2.0.2.

The Vulnerability Explained

How brace-expansion works

The brace-expansion package expands shell-like brace patterns into arrays. For example:

"{a,b}{c,d}" → ["ac", "ad", "bc", "bd"]

This is used by minimatch for glob pattern matching, which in turn powers file system operations in many Node.js applications.

The unbounded intermediate array problem

During expansion, brace-expansion processes nested patterns iteratively. Each level of nesting multiplies the intermediate result array. The CVE-2026-14257 fix added a check on the final output size, but CVE-2026-69152 exploits the fact that intermediate arrays generated between expansion steps have no such bounds.

Consider a crafted input like:

"{a{1..9999},b{1..9999}}{c{1..9999},d{1..9999}}"

Before the final output check kicks in, the intermediate expansion of inner braces creates massive temporary arrays. An attacker can craft patterns where these intermediate arrays grow exponentially while the final output appears bounded—effectively bypassing the prior mitigation.

The vulnerable dependency tree

In exia-invasion/package-lock.json, the vulnerable versions were:

"node_modules/brace-expansion": {
  "version": "1.1.12",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
  "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="
}

And the nested version under readdir-glob:

"node_modules/readdir-glob/node_modules/brace-expansion": {
  "version": "2.0.2",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
  "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="
}

Attack scenario

If the exia-invasion application processes user-supplied glob patterns (e.g., for file selection, search filtering, or path matching), an attacker could submit a specially crafted brace pattern that triggers exponential intermediate array growth. This would cause:

  1. Memory exhaustion: The Node.js process allocates gigabytes of memory for intermediate arrays
  2. Process crash: The system runs out of memory, triggering an OOM kill
  3. Service unavailability: The application becomes unresponsive to legitimate requests

Even if the application doesn't directly expose glob matching to users, any code path where minimatch or readdir-glob processes partially user-influenced patterns (directory names, file filters) could be exploited.

The Fix

Changes made

The fix upgrades brace-expansion across the entire dependency tree to version 1.1.18, which enforces bounds on intermediate array growth during expansion.

Before — vulnerable brace-expansion 1.1.12 at the top level:

"node_modules/brace-expansion": {
  "version": "1.1.12",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
  "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="
}

After — patched brace-expansion 1.1.18:

"node_modules/brace-expansion": {
  "version": "1.1.18",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
  "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="
}

Eliminating the nested vulnerable version

The fix also removes the nested brace-expansion 2.0.2 under readdir-glob/node_modules/ and replaces it with a properly scoped 1.1.18 instance under readdir-glob/node_modules/minimatch/node_modules/:

Before — vulnerable nested version:

"node_modules/readdir-glob/node_modules/brace-expansion": {
  "version": "2.0.2",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
  "dependencies": {
    "balanced-match": "^1.0.0"
  }
}

After — patched version scoped correctly:

"node_modules/readdir-glob/node_modules/minimatch/node_modules/brace-expansion": {
  "version": "1.1.18",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
  "dependencies": {
    "balanced-match": "^1.0.0",
    "concat-map": "0.0.1"
  }
}

Why both changes matter

  1. Top-level upgrade (1.1.12 → 1.1.18): Fixes the primary brace-expansion used by most of the dependency tree
  2. Nested version restructuring (2.0.2 removed, 1.1.18 added under minimatch): Ensures readdir-glob's minimatch dependency also uses a patched version, preventing the vulnerability from lurking in a transitive dependency

The version 1.1.18 adds intermediate array size checks that abort expansion before memory can be exhausted, regardless of how the pattern is structured.

Prevention & Best Practices

Dependency management

  1. Pin and audit dependencies regularly: Use npm audit or dedicated tools like Trivy to scan package-lock.json for known vulnerabilities
  2. Understand transitive dependencies: The nested brace-expansion 2.0.2 under readdir-glob demonstrates how vulnerabilities hide in transitive dependencies
  3. Use lock file integrity checks: The integrity field in package-lock.json ensures you're getting the exact expected package bytes

Input validation

  1. Limit pattern complexity: If your application processes user-supplied glob patterns, enforce maximum length and nesting depth before passing to minimatch
  2. Timeout pattern expansion: Wrap glob operations in timeouts to prevent runaway expansion from blocking the event loop

Monitoring

  1. Memory usage alerts: Set up monitoring for sudden memory spikes that could indicate DoS exploitation
  2. Rate limiting: Apply rate limits to endpoints that process glob or pattern-matching operations

Relevant standards

  • CWE-400: Uncontrolled Resource Consumption
  • OWASP: Application Denial of Service prevention guidelines
  • Node.js Security Best Practices: Regular dependency updates and auditing

Key Takeaways

  • Bypass vulnerabilities are real: CVE-2026-69152 specifically bypasses CVE-2026-14257's mitigation by exploiting intermediate array growth rather than final output size—always verify that security fixes cover all code paths
  • Nested dependencies in package-lock.json can harbor separate vulnerable versions: The readdir-glob/node_modules/brace-expansion at 2.0.2 was a distinct vulnerable instance from the top-level 1.1.12
  • Even "utility" packages like brace-expansion can be high-severity attack vectors: This package is used by minimatch, which is one of the most depended-upon packages in the npm ecosystem
  • Lock file restructuring may be necessary: Simply bumping a version number isn't always sufficient—the fix required removing a nested dependency and re-scoping it under the correct parent
  • DoS vulnerabilities in pattern expansion libraries affect any application processing user-influenced file paths or glob patterns

How Orbis AppSec Detected This

  • Source: User-influenced input reaching glob pattern processing (file paths, search patterns, or directory filters passed to minimatch or readdir-glob)
  • Sink: brace-expansion expansion function in node_modules/brace-expansion/index.js where intermediate arrays are generated without bounds
  • Missing control: No intermediate array size limit during brace expansion steps—only final output was bounded by the CVE-2026-14257 fix
  • CWE: CWE-400 (Uncontrolled Resource Consumption)
  • Fix: Upgraded brace-expansion from 1.1.12 and 2.0.2 to 1.1.18 across the dependency tree, which enforces intermediate array bounds during expansion

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-69152 is a stark reminder that security patches aren't always complete on the first attempt. The original CVE-2026-14257 fix addressed final output bounds but left intermediate arrays unchecked—a gap that attackers could exploit to achieve the same DoS effect. By upgrading brace-expansion to 1.1.18 and restructuring the nested dependency tree, the exia-invasion project eliminates both the direct and transitive exposure to this vulnerability.

For any Node.js project using minimatch, readdir-glob, or any package that depends on brace-expansion, verify your package-lock.json contains version 1.1.18+, 2.1.4+, 3.0.6+, or 5.0.9+ depending on your major version line. Run npm audit today to check.

References

Frequently Asked Questions

What is a DoS via unbounded intermediate arrays?

It's a vulnerability where an algorithm generates exponentially growing temporary data structures during processing, consuming all available memory and causing the application to crash or become unresponsive.

How do you prevent DoS via resource exhaustion in Node.js?

Keep dependencies updated, enforce input length limits on patterns processed by expansion libraries, implement timeouts on pattern processing, and use dependency scanning tools to catch known vulnerable versions.

What CWE is unbounded resource consumption?

CWE-400 (Uncontrolled Resource Consumption), which covers scenarios where an attacker can trigger excessive use of CPU, memory, or other resources.

Is the CVE-2026-14257 mitigation enough to prevent this DoS?

No. CVE-2026-69152 specifically bypasses the CVE-2026-14257 mitigation by exploiting a different code path that generates unbounded intermediate arrays before the prior size check is applied.

Can static analysis detect this vulnerability?

Yes. Tools like Trivy can identify known vulnerable package versions in lock files. Runtime detection requires monitoring memory usage patterns during brace expansion operations.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #21

Related Articles

high

How Client-Side Denial of Service happens in Node.js FTP clients and how to fix it

CVE-2026-44240 is a client-side Denial of Service vulnerability in the `basic-ftp` Node.js package (versions prior to 5.3.1) caused by improper handling of unterminated multiline FTP server responses. An attacker controlling an FTP server—or capable of intercepting FTP traffic—could send a malformed response that causes the client to hang indefinitely. Upgrading `basic-ftp` to 5.3.1 and adding a package override in `package.json` closes the attack surface entirely.

high

How javascript.express.security.audit.express-check-csurf-middleware-usage.express-check-csurf-middleware-usage happens in Express.js and how to fix it

A publicly accessible Express.js API endpoint in `app/api/cameras.js` was missing CSRF protection, leaving state-changing requests (POST, PUT, DELETE, PATCH) vulnerable to cross-site request forgery attacks. The fix introduces Origin/Referer header validation middleware in `app/index.js` and removes a redundant Express instance from `cameras.js` that bypassed the application's middleware chain.

critical

How Command Injection via Unescaped Line Terminators Happens in Node.js and How to Fix It

A critical command injection vulnerability (CVE-2026-9277) was discovered in the shell-quote npm package version 1.8.3, where unescaped line terminators could allow attackers to execute arbitrary code. This fix upgrades shell-quote to version 1.9.0 using npm overrides to ensure all instances in the dependency tree are patched, eliminating the attack vector across the entire application.

critical

How Distributed Lock Takeover Happens in Node.js and How to Fix It

A critical vulnerability in `redis-lock/server.mjs` allowed any authenticated client to release another client's lock by guessing predictable holder identifiers like process IDs or hostnames. The fix implements cryptographically random `lockId` values that are minted on lock acquisition and validated on release, eliminating the exploit primitive entirely.

high

How Denial of Service via Infinite Loop happens in JavaScript (nanoid) and how to fix it

A high-severity denial of service vulnerability (CVE-2026-67213) was discovered in nanoid versions before 5.1.6 and 3.3.18, where the `customAlphabet` function could enter an infinite loop during random ID generation. The fix upgrades the transitive nanoid dependency from 3.3.16 to 3.3.18 using pnpm overrides, ensuring the vulnerable code path is eliminated from the entire dependency tree including PostCSS.

high

How Information Disclosure via Unstripped Credential Headers Happens in Electron Apps and How to Fix It

A high-severity vulnerability (CVE-2026-54673) in the builder-util-runtime package allowed sensitive credential headers to leak during HTTP redirects in Electron applications. The fix upgrades builder-util-runtime from version 9.5.1 to 9.7.0, which properly strips authentication headers before following redirects to prevent information disclosure.