Back to Blog
high SEVERITY5 min read

How Exponential-Time Complexity Causes Denial of Service in brace-expansion and How to Fix It

A critical vulnerability in brace-expansion versions 1.1.13 and earlier allowed attackers to cause denial of service through crafted brace pattern inputs. The fix upgrades to patched versions 1.1.16, 2.1.2, and 5.0.7, eliminating the exponential-time complexity that made exploitation possible.

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

Answer Summary

CVE-2026-13149 is a Regular Expression Denial of Service (ReDoS) vulnerability in brace-expansion 1.1.13, a JavaScript library used for brace pattern matching in glob expressions. The vulnerability stems from exponential-time complexity in brace pattern parsing (CWE-400: Uncontrolled Resource Consumption). The fix upgrades brace-expansion to patched versions 1.1.16, 2.1.2, and 5.0.7 using npm overrides, which implement algorithmic improvements to prevent catastrophic backtracking on malicious inputs.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade brace-expansion to patched versions (1.1.16, 2.1.2, 5.0.7) via npm overrides
riskDenial of Service through CPU exhaustion
languageJavaScript/Node.js
root causeExponential-time complexity in brace pattern expansion algorithm
vulnerabilityRegular Expression Denial of Service (ReDoS) / Algorithmic Complexity Attack

Introduction

In a production web application handling user-influenced file patterns, we discovered a HIGH severity denial of service vulnerability lurking in package-lock.json. The brace-expansion package at version 1.1.13—a dependency likely pulled in through glob-matching utilities—contained an algorithmic flaw that could freeze your entire Node.js process with a single malicious input.

The vulnerable code in node_modules/brace-expansion at line 9603 of package-lock.json showed:

"node_modules/brace-expansion": {
  "version": "1.1.13",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
  "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",

This version string—1.1.13—is the smoking gun. When brace-expansion processes nested brace patterns, the algorithm's time complexity grows exponentially with input depth. For a web application accepting user-provided glob patterns, this creates a trivial denial of service vector.

The Vulnerability Explained

What brace-expansion Does

Brace-expansion is a core JavaScript library that expands brace patterns like file-{1,2,3}.txt into file-1.txt, file-2.txt, file-3.txt. It's a dependency of glob, minimatch, and countless other packages—making this vulnerability extremely widespread.

The Algorithmic Flaw

The vulnerability in version 1.1.13 stems from exponential-time complexity in the brace expansion algorithm. Consider this pattern:

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

Each nested brace doubles the computation. With 10 levels, this generates 2^10 = 1,024 combinations. With 25 levels, you get 33,554,432 combinations. The algorithm doesn't implement:

  • Depth limiting
  • Memoization to avoid redundant computations
  • Early termination on excessive expansion

Real-World Attack Scenario

In our web application context, imagine an endpoint accepting a pattern parameter for file search:

// Hypothetical vulnerable endpoint
app.get('/search', (req, res) => {
  const pattern = req.query.pattern;  // User-controlled!
  const files = glob.sync(pattern);   // Uses brace-expansion internally
  res.json(files);
});

An attacker sends:

GET /search?pattern={a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}{a,b}

The server hangs. CPU spikes to 100%. Other requests timeout. Depending on the Node.js configuration, this could crash the process or exhaust resources until manual intervention.

The package-lock.json entry at line 9603 confirmed this vulnerable version was in the production dependency tree—not devDependencies, meaning it reached actual users.

The Fix

The remediation involved two coordinated changes to enforce patched versions across the dependency tree.

Change 1: Direct Dependency Update in package-lock.json

Before (vulnerable):

"node_modules/brace-expansion": {
  "version": "1.1.13",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
  "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",

After (patched):

"node_modules/brace-expansion": {
  "version": "1.1.16",
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
  "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",

Version 1.1.16 (and the parallel releases 2.1.2 and 5.0.7) implement algorithmic fixes:

  • Linear-time expansion: Restructured recursion to avoid exponential blowup
  • Depth limiting: Maximum brace nesting prevents abuse
  • Early termination: Stops expansion when output would exceed reasonable bounds

Change 2: npm Overrides in package.json

The package.json received a critical addition at line 93:

,
  "overrides": {
    "brace-expansion": "1.1.16"
  }
}

This overrides field (npm 8.3+) forces all transitive dependencies to use the specified version, regardless of what their own package.json requests. This is essential because:

  • glob might require brace-expansion ^1.1.0
  • minimatch might require brace-expansion ^2.0.0
  • Other packages might pull in vulnerable versions

Without overrides, you'd need to wait for every upstream maintainer to update. The override cuts through the dependency tree immediately.

Why Three Versions?

The PR mentions 5.0.7, 1.1.16, and 2.1.2 because brace-expansion has multiple major version lines in active use:

Version Line Use Case Fix Version
1.x Legacy glob/minimatch 1.1.16
2.x Modern minimatch 2.1.2
5.x Current standalone 5.0.7

The overrides in this project targets 1.1.16 specifically for the 1.x line used by its direct dependencies.

Prevention & Best Practices

Dependency Management

  1. Audit regularly: Run npm audit and tools like Trivy in CI/CD
  2. Pin with purpose: Use exact versions for security-critical packages
  3. Override aggressively: Don't wait for upstream—use overrides or resolutions (Yarn) to force security patches

Input Handling

// Defensive pattern for user-provided globs
const MAX_PATTERN_LENGTH = 500;
const MAX_BRACE_DEPTH = 5;

function sanitizeGlobPattern(pattern) {
  if (pattern.length > MAX_PATTERN_LENGTH) {
    throw new Error('Pattern too long');
  }

  const braceDepth = (pattern.match(/\{/g) || []).length;
  if (braceDepth > MAX_BRACE_DEPTH) {
    throw new Error('Excessive brace nesting');
  }

  return pattern;
}

Detection Tools

Tool Command Purpose
Trivy trivy fs . Scans package-lock.json for CVEs
npm audit npm audit Native Node.js vulnerability check
Snyk snyk test Dependency vulnerability scanning
Semgrep semgrep --config=auto Custom ReDoS pattern detection

Standards & References

  • CWE-400: Uncontrolled Resource Consumption
  • CWE-1333: Inefficient Regular Expression Complexity (related)
  • OWASP: ReDoS Cheat Sheet

Key Takeaways

  • The package-lock.json at line 9603 contained brace-expansion@1.1.13, which has exponential-time complexity on nested brace patterns—always audit your lockfile, not just package.json
  • Use npm overrides (or Yarn resolutions) to force security patches when upstream dependencies lag, rather than waiting for transitive updates
  • Algorithmic complexity attacks bypass traditional input validation—the input looks valid but consumes excessive resources; depth limits and timeouts are essential
  • Multiple major version lines require parallel fixes—brace-expansion 1.x, 2.x, and 5.x all needed separate patches, so verify which line your project uses
  • Production code assessment matters—Trivy correctly flagged this as "likely exploitable" because the dependency was in the production dependency tree, not dev-only

How Orbis AppSec Detected This

Source: User-influenced input entering through HTTP request parameters (e.g., pattern query parameter) that flow into glob-matching operations

Sink: The brace-expansion package's pattern expansion algorithm in node_modules/brace-expansion/index.js, invoked through transitive dependencies like glob or minimatch

Missing control: No input length limits, no brace nesting depth validation, and no execution timeouts on pattern expansion operations; the package-lock.json contained the vulnerable version 1.1.13 without overrides

CWE: CWE-400: Uncontrolled Resource Consumption (Algorithmic Complexity)

Fix: Upgraded brace-expansion to patched versions 1.1.16, 2.1.2, and 5.0.7 and added an overrides entry in package.json to force all transitive dependencies onto secure versions

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-13149 exemplifies how a seemingly simple utility library can become a critical attack vector. The brace-expansion vulnerability didn't require exotic exploits—just a basic understanding of algorithmic complexity and a crafted HTTP request. The fix demonstrates modern dependency management best practices: don't just upgrade direct dependencies, use overrides to secure your entire dependency tree immediately.

For Node.js developers, this is a reminder that package-lock.json is a security surface. Tools like Trivy caught this vulnerability in CI, and automated fixes like Orbis AppSec can apply the patches before attackers exploit them. Keep your dependencies updated, implement defense-in-depth with input limits, and never underestimate the damage from exponential complexity.


References

Frequently Asked Questions

What is brace-expansion ReDoS?

A denial of service vulnerability where specially crafted brace patterns (like `{a,b}{a,b}{a,b}...`) cause exponential computation time, freezing the application.

How do you prevent ReDoS in JavaScript?

Use libraries with linear-time algorithms, implement input length limits, apply timeouts on pattern matching, and keep dependencies updated.

What CWE is brace-expansion ReDoS?

CWE-400: Uncontrolled Resource Consumption, specifically through algorithmic complexity.

Is input validation alone enough to prevent brace-expansion ReDoS?

No, while helpful, the root fix is upgrading to patched library versions that fix the underlying algorithmic flaw.

Can static analysis detect brace-expansion ReDoS?

Yes, scanners like Trivy can detect vulnerable dependency versions in package-lock.json and package.json files.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #736

Related Articles

critical

How a vulnerable websocket-driver dependency happens in Node.js lockfiles and how to fix it

A Trivy scan flagged `websocket-driver@0.7.4` in this repository's `bun.lock` as affected by CVE-2026-54466, a critical issue in a WebSocket protocol handler that parses untrusted HTTP upgrade requests and frame data. The fix upgrades the package to `0.7.5` and adds an explicit `websocket-driver` entry to the lockfile's override block so every transitive consumer — webpack-dev-server, sockjs, faye-websocket — resolves to the patched build instead of the pinned vulnerable one.

high

How Dependabot Missing Cooldown Periods Enable Supply Chain Attacks and How to Fix It

A critical security vulnerability in `.github/dependabot.yml` was exposing a Node.js library to supply chain attacks by automatically updating to newly published packages without a safety delay. By adding a 7-day cooldown period to each package ecosystem configuration, the project now protects against malicious or unstable package versions that could affect downstream consumers.

high

How unrestricted file upload via extension-only validation happens in Deno/JavaScript and how to fix it

The review image upload handler in this Deno-based app trusted the client-supplied filename extension to decide whether a file was a "safe" image, without ever inspecting the actual file bytes. The fix adds magic-byte signature verification for PNG, JPEG, GIF, and WEBP formats before the file is written to disk, closing the door on disguised executables and malicious payloads.

high

How Missing Dependabot Cooldown Periods Enable Supply Chain Attacks in CI/CD Pipelines and How to Fix Them

We fixed a high-severity supply chain security gap in `.github/dependabot.yml` where missing cooldown periods allowed immediate adoption of newly published packages. The fix adds `cooldown: default-days: 7` to all package ecosystems, creating a critical security buffer against typosquatting and malicious dependency attacks.

high

How Dependabot Missing Cooldown Vulnerability Happens in GitHub Actions and How to Fix It

Dependabot configurations without cooldown periods can automatically propose updates from newly published packages within hours—potentially including malicious or unstable versions. This vulnerability in `.github/dependabot.yml` was fixed by adding a `cooldown` block with `default-days: 7` to delay updates and allow time for community vetting.

high

How dependabot-missing-cooldown happens in GitHub Actions configuration and how to fix it

A high-severity vulnerability in `.github/dependabot.yml` left this repository vulnerable to supply chain attacks through immediate adoption of newly published packages. The fix adds a mandatory 7-day cooldown period to all three package ecosystems, preventing automatic updates to potentially malicious or unstable dependencies before they can be vetted by the community.