Back to Blog
high SEVERITY4 min read

CVE-2026-73089: browserslist 4.28.1 DoS via Query Result Caching

CVE-2026-73089 is a high-severity denial-of-service vulnerability in browserslist versions before 4.28.7. The issue stems from unbounded memory growth when caching results from distinct browser queries, eventually causing out-of-memory crashes in build processes and development servers.

O
By Orbis AppSec
•Published October 1, 2026•Reviewed October 1, 2026

Answer Summary

browserslist versions 4.28.1 and earlier are affected. An attacker who can influence browser query strings (such as through build configuration or environment variables) can trigger unbounded memory growth in the query result cache, eventually exhausting available memory and crashing the process. The fix upgrades browserslist to 4.28.7, which includes updated dependencies that properly bound cache growth. CWE is unknown.

Vulnerability at a Glance

cweN/A
fixUpgrade browserslist to 4.28.7 with bounded cache dependencies
riskBuild process or dev server crashes from memory exhaustion
languageJavaScript
root causeQuery result cache grows without bound when processing distinct browser queries
vulnerabilityDenial of Service via unbounded memory growth

Affected Versions

Affected >= 4.0.0, < 4.28.7
Fixed in 4.28.7
Ecosystem npm
CVE / GHSA CVE-2026-73089 / not assigned
CWE unknown

The Vulnerability Explained

The browserslist library powers build tools across the JavaScript ecosystem—Babel, PostCSS, and webpack all rely on it to determine which browser versions to target. When you write > 0.5%, last 2 versions in your .browserslistrc file, browserslist parses this into concrete browser queries and caches the results for performance.

CVE-2026-73089 exposes a critical flaw in this caching mechanism. The baseline-browser-mapping dependency, which browserslist uses to resolve caniuse-lite data into browser version mappings, maintains an in-memory cache of query results. Prior to version 2.11.22, this cache grew without bound when processing distinct query strings.

Here's how the vulnerable dependency resolution appeared:

"node_modules/browserslist": {
  "version": "4.28.1",
  "dependencies": {
    "baseline-browser-mapping": "^2.9.0",
    "caniuse-lite": "^1.0.30001759",
    "electron-to-chromium": "^1.5.263",
    "node-releases": "^2.0.27",
    "update-browserslist-db": "^1.2.0"
  }
}

The baseline-browser-mapping at ^2.9.0 (resolved to 2.10.0 in practice) creates a new cache entry for every unique query string it encounters. In long-running processes—such as webpack's development server with hot module reloading—or in CI pipelines processing multiple builds with varying configurations, these distinct queries accumulate indefinitely. Each entry stores the full mapping data, which can reach hundreds of kilobytes per query.

An attacker doesn't need direct code execution. Consider a SaaS platform that lets users configure custom build pipelines: if user-supplied strings reach browserslist() API calls without normalization, each unique configuration becomes a memory leak. Similarly, automated fuzzing of build configurations could exhaust memory in minutes.

The Fix

The resolution upgrades browserslist to 4.28.7, which transitively pulls in baseline-browser-mapping 2.11.22. This version implements proper cache bounds with LRU (Least Recently Used) eviction, preventing unbounded growth.

The dependency changes in the fixed version:

"node_modules/browserslist": {
  "version": "4.28.7",
  "dependencies": {
    "baseline-browser-mapping": "^2.10.44",
    "caniuse-lite": "^1.0.30001806",
    "electron-to-chromium": "^1.5.393",
    "node-releases": "^2.0.51",
    "update-browserslist-db": "^1.1.1"
  }
}

The baseline-browser-mapping bump from 2.10.0 to 2.11.22 is the critical change. Version 2.10.44 in the semver range ensures the bounded cache implementation is present. The accompanying updates to caniuse-lite, electron-to-chromium, and node-releases provide current browser data but aren't security fixes themselves.

This fix demonstrates a common supply-chain pattern: the vulnerability wasn't in browserslist's own code, but in a transitive dependency's internal implementation. The browserslist maintainers correctly identified this and tightened their dependency constraints to exclude the vulnerable baseline-browser-mapping versions.

Key Takeaways

  • Cache bounds are security boundaries: Any unbounded cache that accepts potentially attacker-influenced keys is a memory exhaustion vector. LRU eviction with size limits should be the default pattern.

  • Transitive dependencies require explicit version management: The vulnerable code was two levels deep in the dependency tree. Tools like npm audit and trivy catch these, but only if you scan lockfiles, not just package.json declarations.

  • Long-running build processes amplify memory leaks: What might seem like a minor caching issue becomes critical in development servers and CI pipelines that run for hours or process thousands of builds.

  • Query normalization before caching prevents distinct-key attacks: If you accept user-influenced browser queries, normalize them (deduplicate equivalent strings, enforce a whitelist) before passing to browserslist to reduce cache key explosion.

How Orbis AppSec Detected This

Source: User-influenced input reaching the browserslist() API through configuration files, environment variables (BROWSERSLIST_ENV, BROWSERSLIST_CONFIG), or programmatic query strings.

Sink: The internal cache in baseline-browser-mapping version 2.10.0, which stores query results without size limits.

Missing control: Cache eviction bounds and maximum size limits on the baseline-browser-mapping result cache.

CWE: unknown

Fix: Upgrade browserslist to 4.28.7, which depends on baseline-browser-mapping 2.11.22 with implemented LRU cache eviction.

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-73089 reminds us that even utility libraries like browserslist—trusted by millions of builds daily—can harbor subtle resource exhaustion flaws. The unbounded cache in baseline-browser-mapping 2.10.0 created a denial-of-service path that required no network access, no authentication, and no complex exploitation—just distinct query strings over time. Upgrading to browserslist 4.28.7 closes this vector with minimal disruption, but the broader lesson stands: treat all caches as potential attack surfaces, and bound them accordingly.

Prevention and further reading

Frequently Asked Questions

Does browserslist 4.28.7 change the query syntax or break existing `.browserslistrc` files?

No, the upgrade is fully backward-compatible. The fix only affects internal caching behavior in the `baseline-browser-mapping` dependency, not the public query API.

Can the memory exhaustion be triggered through the `BROWSERSLIST_ENV` environment variable?

Yes, any channel that influences query strings—including environment variables, configuration files, or programmatic API calls—can trigger distinct cache entries. The vulnerability is not limited to one input vector.

Why does the fix require updating `baseline-browser-mapping` from 2.10.0 to 2.11.22 rather than patching browserslist directly?

The unbounded growth originates in `baseline-browser-mapping`'s internal caching layer. browserslist 4.28.7 pins the corrected version (2.11.22) which implements proper cache eviction, solving the root cause without changes to browserslist's own code.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #15

Related Articles

high

XShmGetImage Heap Corruption: Unvalidated Image Height in streamproxy

The `XShmGetImage` function in the X11 shared memory image path copies pixel data row-by-row using `memcpy` without validating that the source image height matches the destination buffer height. An attacker or compromised server could provide an oversized source image, causing writes beyond the allocated heap buffer and triggering heap corruption or code execution.

critical

SGX Enclave ecall_store_data memcpy Buffer Overflow in 256-Byte

The Intel SGX enclave's trusted bridge functions `ecall_store_data` and `ecall_retrieve_data` used `memcpy()` to move data into and out of a fixed 256-byte `secure_storage` buffer without validating that `data_len` fit within destination boundaries. An attacker providing oversized `data_len` values could corrupt enclave memory, breaking SGX's confidentiality guarantees.

critical

How buffer overflow happens in C++ and how to fix it

A critical buffer overflow in `create_hex_string()` within `hmlangw.cpp` let an unconditional 16-iteration loop write past the bounds of a 100-byte `hex` buffer using unchecked `sprintf` calls. The fix replaces `sprintf` with `snprintf` and caps the loop iterations based on the actual destination buffer size, closing off a memory corruption path reachable from serial or network input.

high

How remote memory exhaustion happens in Rust QUIC (Quinn) and how to fix it

A high-severity vulnerability (GHSA-4w2j-m93h-cj5j) in `quinn-proto`, the QUIC protocol implementation underlying the Quinn library, allowed remote attackers to exhaust server memory by sending unbounded out-of-order stream data. The `crosshash` project's `Cargo.lock` pinned the vulnerable `quinn-proto` 0.11.14; upgrading to 0.11.15 closes the gap by bounding how much out-of-order stream data the reassembly buffer will retain.

high

How Denial-of-Service via Unbounded Brace Expansion Happens in Node.js and How to Fix It

A critical denial-of-service vulnerability in the `brace-expansion` package allowed attackers to exhaust process memory through unbounded intermediate array expansion. The fix upgrades the package to patched versions (1.1.18, 2.1.4, 3.0.6, 5.0.9) that implement proper expansion length limits, preventing out-of-memory crashes in production applications.

high

js-yaml 5.2.1 DoS: Exponential Parsing in Flow Collections

A denial-of-service vulnerability in js-yaml 5.2.1 allows an attacker to crash the parser by supplying deeply nested flow collections that trigger exponential parsing behavior. The fix in version 5.2.2 improves the parser's handling of these structures, preventing the algorithmic complexity attack. This is critical for any service accepting user-controlled YAML input.