Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-73088

CVE-2026-73088: Browserslist Prototype Pollution Vulnerability

CVE-2026-73088 is a prototype pollution flaw in Browserslist that allows attackers to modify object prototypes through untrusted input. This article covers the technical details, affected versions, impact, and mitigation.

Published:

CVE-2026-73088 Overview

CVE-2026-73088 is a prototype pollution vulnerability in Browserslist, a widely used configuration tool that shares target browser and Node.js version data across front-end tooling. The flaw resides in the normalizeStats() function within node.js, which is reached unconditionally through getStat() and loadStat() on every browserslist() call. The function processes untrusted browserslist-stats.json, opts.stats, and CLI --stats inputs using an unguarded for...in loop combined with plain-object bracket assignment. Attackers who control stats input can inject inherited Object.prototype keys such as __proto__, toString, valueOf, constructor, hasOwnProperty, and isPrototypeOf. The issue is fixed in version 4.28.7.

Critical Impact

Malicious stats input can trigger uncaught TypeError exceptions or modify the prototype of the returned normalized object, resulting in denial of service or downstream logic corruption in build pipelines.

Affected Products

  • Browserslist versions prior to 4.28.7
  • Front-end build tooling that consumes untrusted browserslist-stats.json
  • CI/CD pipelines invoking browserslist with attacker-controlled --stats input

Discovery Timeline

  • 2026-08-11 - CVE-2026-73088 published to NVD
  • 2026-08-13 - Last updated in NVD database

Technical Details for CVE-2026-73088

Vulnerability Analysis

Browserslist parses regional and custom usage statistics through the normalizeStats() routine. The function iterates over caller-supplied stats using a for...in loop, which enumerates inherited properties from Object.prototype. Because the destination object is created as a plain {} literal, bracket assignments such as normalized[i] = ... can write to prototype-inherited slots or trigger accessor-related errors.

When a payload includes a key like __proto__, the assignment either throws an uncaught TypeError or mutates the prototype chain of the returned object. Downstream consumers that expect a well-formed normalized stats object may then invoke coerced methods (toString, valueOf) that no longer behave as expected, breaking the build or corrupting logic that iterates the result. This falls under [CWE-248] Uncaught Exception.

Root Cause

The root cause is unsafe object construction combined with unfiltered property enumeration. normalizeStats() uses var normalized = {} and iterates with for (var i in stats) without an Object.prototype.hasOwnProperty.call() guard. Bracket access on the source data[i] also trusts inherited keys instead of verifying own-property ownership.

Attack Vector

An attacker supplies a crafted browserslist-stats.json file, a poisoned opts.stats object, or CLI --stats argument. When any downstream tool invokes browserslist(), the malicious stats are processed automatically. No authentication or user interaction is required, and exploitation is network-reachable in scenarios where stats files travel through package dependencies or shared build artifacts.

javascript
// Security patch in node.js - Fix prototype write
  if (typeof stats !== 'object') return undefined

-  var normalized = {}
+  var normalized = Object.create(null)
   for (var i in stats) {
     var versions = Object.keys(stats[i])
-    if (versions.length === 1 && data[i] && data[i].versions.length === 1) {
-      var normal = data[i].versions[0]
-      normalized[i] = {}
+    var known = Object.prototype.hasOwnProperty.call(data, i) && data[i]
+    if (versions.length === 1 && known && known.versions.length === 1) {
+      var normal = known.versions[0]
+      normalized[i] = Object.create(null)
       normalized[i][normal] = stats[i][versions[0]]
     } else {
       normalized[i] = stats[i]

Source: GitHub Commit f9914ad. The patch replaces the plain object literal with Object.create(null) to eliminate the prototype chain and adds an explicit hasOwnProperty guard against the data lookup.

Detection Methods for CVE-2026-73088

Indicators of Compromise

  • Presence of __proto__, constructor, prototype, toString, valueOf, hasOwnProperty, or isPrototypeOf keys inside any browserslist-stats.json file.
  • Build process crashes with TypeError originating from normalizeStats in the browserslist/node.js stack trace.
  • Unexpected changes to shared object behavior in Node.js build tooling after loading custom stats files.

Detection Strategies

  • Statically scan repositories and package caches for browserslist-stats.json files containing reserved prototype keys.
  • Inspect package-lock.json and yarn.lock for browserslist versions below 4.28.7 across all transitive dependencies.
  • Instrument CI runners to capture and alert on uncaught TypeError events emitted during browserslist invocations.

Monitoring Recommendations

  • Enable Software Composition Analysis (SCA) rules that flag vulnerable browserslist versions in build pipelines.
  • Monitor npm advisory feeds and subscribe to GHSA-73wf-gq98-2v4g for updates.
  • Log and review all external sources of --stats input passed to build tools.

How to Mitigate CVE-2026-73088

Immediate Actions Required

  • Upgrade browserslist to version 4.28.7 or later across all direct and transitive dependencies.
  • Audit build repositories for untrusted browserslist-stats.json files and remove any containing prototype-reserved keys.
  • Rebuild and redeploy artifacts produced by pipelines that consumed potentially malicious stats input.

Patch Information

The fix is available in Browserslist Release 4.28.7. It replaces plain object literals with Object.create(null) and validates own-property access with Object.prototype.hasOwnProperty.call(). See the GitHub Commit Details for the complete patch diff.

Workarounds

  • Restrict the source of browserslist-stats.json to trusted, version-controlled files reviewed by maintainers.
  • Sanitize any dynamic opts.stats object by deleting reserved keys such as __proto__ and constructor before invoking browserslist().
  • Avoid passing untrusted CLI --stats arguments in shared build environments until the upgrade is complete.
bash
# Upgrade browserslist across the dependency tree
npm install browserslist@^4.28.7 --save
npm update browserslist
npm ls browserslist

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.