Skip to content

Prototype Pollution in json-validator via validate #15

@gnsehfvlr

Description

@gnsehfvlr

Prototype Pollution in json-validator

Summary

json-validator (<= 0.0.34) is vulnerable to Prototype Pollution via the validate function.

Description

The validate() function recursively traverses schema/data objects without filtering __proto__ keys. When validating untrusted JSON data against a schema, an attacker can inject __proto__ properties that pollute Object.prototype. This is particularly dangerous because validation functions are expected to be safe to call with untrusted input.

Proof of Concept

const jsonValidator = require("json-validator");

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

const malicious = JSON.parse('{"__proto__":{"polluted":"yes"}}');
jsonValidator.validate({}, malicious);

console.log("After:", ({}).polluted); // "yes"

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, ({}).polluted === "yes" on every newly created object in the entire Node.js process
  2. The pollution is silent — no error is thrown, no warning is logged. The caller has no indication that the global prototype was modified
  3. Any downstream code is affected — authentication checks (if (user.isAdmin)), serialization, template rendering, database queries — all inherit the polluted properties
  4. This is a well-documented vulnerability class with numerous CVEs assigned for the same pattern: CVE-2020-8203 (lodash), CVE-2021-25945 (js-extend)

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/authorized properties
  • Property Injection — all objects inherit polluted properties

Remediation

Filter dangerous keys during recursive object traversal:

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

// Add this check in the recursive merge loop:
if (UNSAFE_KEYS.has(key)) continue;

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    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