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
•Technically reviewed by Anupam Mediratta•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.

high

How Inherited libvips Vulnerabilities in sharp Impact Image Processing and How to Fix Them

A critical vulnerability (GHSA-f88m-g3jw-g9cj) was discovered where the sharp image processing library inherited four dangerous libvips vulnerabilities that could be exploited through maliciously crafted images. The fix involved upgrading sharp from version 0.34.5 to 0.35.0, which includes hardened input handling and updated libvips bindings to prevent exploitation of these inherited weaknesses.

critical

How NULL pointer dereference from unchecked malloc() happens in C and how to fix it

A critical memory safety vulnerability was discovered in `bench/tokenizer/tokenizer.c` where `malloc()` was called without checking its return value before passing the pointer to `memcpy()`. If allocation fails and `malloc()` returns NULL, the subsequent `memcpy()` writes to address zero, causing heap corruption or potential arbitrary code execution. The fix adds a single NULL check immediately after allocation, exiting cleanly on failure rather than proceeding with a dangerously invalid pointer

critical

How Buffer Overflow via strcpy() Happens in C++ XML Parsers and How to Fix It

A critical buffer overflow vulnerability was discovered in `buildroot-external/package/libxmlparser/xmlParser.cpp`, where the `toXMLString` function used `_tcscpy()` to write XML escape sequences into a destination buffer without any bounds checking. An attacker supplying a crafted XML document could overflow the buffer and potentially execute arbitrary code. The fix replaces all five unsafe `_tcscpy()` calls with `memcpy()` calls that copy only the exact number of bytes required for each escape

high

picomatch 2.3.1 ReDoS: Extglob Pattern Catastrophic Backtracking

picomatch versions below 2.3.2, 3.0.2, or 4.0.4 contain a Regular Expression Denial of Service vulnerability in extglob pattern parsing. An attacker can cause catastrophic backtracking with patterns containing nested alternations and quantifiers, freezing any Node.js process that evaluates untrusted glob expressions.