Prototype Pollution in zrender-nightly
Summary
zrender-nightly (<= 6.0.1-dev) is vulnerable to Prototype Pollution via the Text.prototype._mergeRich() function.
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.prototype is 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 into Object.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.spawn inherits shell: true from polluted prototype
- Denial of Service (DoS) — overriding
toString/valueOf crashes string coercion
- Authentication Bypass — polluting
isAdmin/role properties
- 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;
References
Prototype Pollution in
zrender-nightlySummary
zrender-nightly(<= 6.0.1-dev) is vulnerable to Prototype Pollution via theText.prototype._mergeRich()function.Description
zrenderis the rendering engine behind Apache ECharts. TheText.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 intoObject.prototypeand 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
Why this is a real vulnerability
Object.prototypeis globally modified — after the PoC runs, every newly created object has the polluted propertyThe root cause is in
_mergeRich()which recursively merges rich text style objects:__proto__, it follows it intoObject.prototypeObject.prototypeAttack scenario: ZRender/ECharts charts accept configuration with rich text styles. If chart data comes from an API or user input:
This is a well-documented vulnerability class — CVE-2020-8203 (lodash) is the same pattern
Impact
child_process.spawninheritsshell: truefrom polluted prototypetoString/valueOfcrashes string coercionisAdmin/rolepropertiesRemediation
Filter dangerous keys in
_mergeRich():References