Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#2239·nvd3

Prototype Pollution in utils.deepExtend() — affects nvd3 and nvd3-fork

Author: gnsehfvlrCreated Mar 27, 2026Updated May 2, 2026

Prototype Pollution in nvd3 / nvd3-fork

Summary

nvd3 (<= 1.8.6) and its fork nvd3-fork (<= 2.0.5) are vulnerable to Prototype Pollution via the utils.deepExtend() function.

  • CWE: CWE-1321 - Improperly Controlled Modification of Object Prototype Attributes
  • Severity: High (CVSS 7.5)
  • Weekly Downloads: nvd3: 62,217 + nvd3-fork: 46,872 = 109,089 combined
  • npm: https://www.npmjs.com/package/nvd3

Description

nvd3 is a popular D3-based charting library. The utils.deepExtend() function recursively merges objects without filtering dangerous keys (__proto__, constructor, prototype). When a source object contains __proto__, the function traverses into Object.prototype and assigns properties to it, polluting all JavaScript objects in the application.

Proof of Concept

javascript
const nv = require("nvd3");

// Before: prototype is clean
console.log("Before:", ({}).polluted); // undefined

// Pollute via deepExtend
const malicious = JSON.parse('{"__proto__":{"polluted":"yes"}}');
nv.utils.deepExtend({}, 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"

The same PoC works with nvd3-fork:

javascript
const nv = require("nvd3-fork");
nv.utils.deepExtend({}, JSON.parse('{"__proto__":{"polluted":"yes"}}'));
console.log(({}).polluted); // "yes"

Why this is a real vulnerability

  1. Object.prototype is globally modified — after calling deepExtend with a crafted payload, ({}).polluted === "yes" on every newly created object in the entire Node.js process

  2. The root cause is in utils.deepExtend() which uses recursive property copying:

    • It iterates over all keys in the source object
    • When it encounters __proto__, it accesses target["__proto__"] which is Object.prototype
    • It then recursively copies properties onto Object.prototype
    • No check is performed to skip __proto__, constructor, or prototype keys
  3. Attack scenario: nvd3 charts accept configuration objects. If chart options come from user-controlled sources (API responses, config files, URL parameters), an attacker can inject __proto__ properties:

    javascript
    // Server renders chart with user-provided options
    const userOptions = JSON.parse(req.body.chartConfig);
    nv.utils.deepExtend(defaultOptions, userOptions);
    // If userOptions = {"__proto__":{"isAdmin":true}} → all objects polluted
  4. This is a well-documented vulnerability class — CVE-2020-8203 (lodash), CVE-2021-25945 (js-extend) are the same pattern

Impact

  • Remote Code Execution (RCE) — child_process.spawn inherits shell: true from polluted prototype, enabling command injection
  • Denial of Service (DoS) — overriding toString/valueOf crashes any string coercion: String({}) throws TypeError
  • Authentication Bypass — polluting isAdmin, role, authorized bypasses downstream authorization checks
  • Property Injection — all newly created objects inherit polluted properties, causing unpredictable application behavior

Remediation

Filter dangerous keys in utils.deepExtend():

javascript
const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);

nv.utils.deepExtend = function(dst) {
    angular.forEach(arguments, function(obj) {
        if (obj !== dst) {
            angular.forEach(obj, function(value, key) {
                if (UNSAFE_KEYS.has(key)) return; // ← ADD THIS LINE
                if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
                    nv.utils.deepExtend(dst[key], value);
                } else {
                    dst[key] = value;
                }
            });
        }
    });
};

References

  • CWE-1321: Improperly Controlled Modification of Object Prototype Attributes
  • CVE-2020-8203 (lodash) — same vulnerability pattern
  • https://www.npmjs.com/package/nvd3
  • https://www.npmjs.com/package/nvd3-fork

Source: novus/nvd3

View original on GitHubView discussion on GitHub