From e6abffce9829893292cf901d0c7902a56cfcd18b Mon Sep 17 00:00:00 2001 From: Marshall Thompson Date: Mon, 10 Aug 2026 11:02:25 -0600 Subject: [PATCH] fix(commons): skip prototype-polluting keys in _.merge Object.keys() returns __proto__ as an own enumerable key for JSON-parsed sources, causing the recursive merge to write onto Object.prototype. Skip __proto__/constructor/prototype keys. Same remediation as dove #3690 / @feathersjs/commons@5.0.45 (GHSA-28xv-ph75-77wh / CVE-2026-54335). Reported-by: Andrew Ridings (@ridingsa) --- packages/commons/src/utils.ts | 5 +++++ packages/commons/test/utils.test.ts | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/commons/src/utils.ts b/packages/commons/src/utils.ts index c6858d4979..25b63e7f59 100644 --- a/packages/commons/src/utils.ts +++ b/packages/commons/src/utils.ts @@ -75,6 +75,11 @@ export const _ = { merge (target: any, source: any) { if (_.isObject(target) && _.isObject(source)) { Object.keys(source).forEach(key => { + // Skip prototype-polluting keys (e.g. JSON-parsed `__proto__`) + if (key === '__proto__' || key === 'constructor' || key === 'prototype') { + return; + } + if (_.isObject(source[key])) { if (!target[key]) { Object.assign(target, { [key]: {} }); diff --git a/packages/commons/test/utils.test.ts b/packages/commons/test/utils.test.ts index 0a3a152f18..25e035db78 100644 --- a/packages/commons/test/utils.test.ts +++ b/packages/commons/test/utils.test.ts @@ -167,6 +167,15 @@ describe('@feathersjs/commons utils', () => { assert.equal(_.merge('hello', {}), 'hello'); }); + + it('merge does not pollute Object.prototype', () => { + _.merge({}, JSON.parse('{"__proto__":{"polluted":"x"}}')); + _.merge({}, JSON.parse('{"constructor":{"prototype":{"polluted2":"y"}}}')); + assert.strictEqual(({} as any).polluted, undefined); + assert.strictEqual(({} as any).polluted2, undefined); + assert.strictEqual((Object.prototype as any).polluted, undefined); + assert.strictEqual((Object.prototype as any).polluted2, undefined); + }); }); describe('makeUrl', function () {