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 auditandtrivycatch these, but only if you scan lockfiles, not justpackage.jsondeclarations. -
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.