Skip to content

Commit bbe30c2

Browse files
committed
fix(utils): prevent prototype pollution in deepMerge
1 parent b9ce077 commit bbe30c2

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

packages/utils/src/__tests__/utils.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,19 @@ describe('Service/Utilies', () => {
604604
e: 2,
605605
});
606606
});
607+
608+
it('should ignore prototype pollution keys while merging objects', () => {
609+
delete (Object.prototype as any).polluted;
610+
611+
const input1 = {};
612+
const input2 = JSON.parse('{"__proto__":{"polluted":"yes"},"constructor":{"prototype":{"polluted":"yes"}},"prototype":{"polluted":"yes"}}');
613+
614+
const output = deepMerge(input1, input2);
615+
616+
expect(output).toEqual({});
617+
expect((Object.prototype as any).polluted).toBeUndefined();
618+
expect(({} as any).polluted).toBeUndefined();
619+
});
607620
});
608621

609622
describe('emptyObject() method', () => {

packages/utils/src/utils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { AnyFunction } from './models/types.js';
22

3+
const unsafeMergeKeys = new Set(['__proto__', 'constructor', 'prototype']);
4+
35
/**
46
* Add an item to an array only when the item does not exists, when the item is an object we will be using their "id" to compare
57
* @param inputArray
@@ -107,7 +109,7 @@ export function deepMerge(target: any, ...sources: any[]): any {
107109

108110
if (isObject(target) && isObject(source)) {
109111
Object.keys(source).forEach((prop) => {
110-
if (source.hasOwnProperty(prop)) {
112+
if (Object.prototype.hasOwnProperty.call(source, prop) && !unsafeMergeKeys.has(prop)) {
111113
if (prop in target) {
112114
// handling merging of two properties with equal names
113115
if (typeof (target as any)[prop] !== 'object') {

0 commit comments

Comments
 (0)