Skip to content

Commit 17740f2

Browse files
committed
Reworked deepmerge's prototype pollution check to use Object.prototype.hasOwnProperty
1 parent 0f80d80 commit 17740f2

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

packages/mui-utils/src/deepmerge/deepmerge.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ describe('deepmerge', () => {
3434
expect({}).not.to.have.property('isAdmin');
3535
});
3636

37+
it('should appropriately copy the fields without prototype pollution', () => {
38+
const result = deepmerge(
39+
{},
40+
JSON.parse('{ "myProperty": "a", "__proto__" : { "isAdmin" : true } }'),
41+
);
42+
43+
// @ts-expect-error __proto__ is not on this object type
44+
// eslint-disable-next-line no-proto
45+
expect(result.__proto__).to.have.property('isAdmin');
46+
expect({}).not.to.have.property('isAdmin');
47+
})
48+
3749
it('should merge objects across realms', function test() {
3850
if (!/jsdom/.test(window.navigator.userAgent)) {
3951
// vm is only available in Node.js.

packages/mui-utils/src/deepmerge/deepmerge.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ export default function deepmerge<T>(
4141

4242
if (isPlainObject(target) && isPlainObject(source)) {
4343
Object.keys(source).forEach((key) => {
44-
// Avoid prototype pollution
45-
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
46-
return;
47-
}
48-
49-
if (isPlainObject(source[key]) && key in target && isPlainObject(target[key])) {
44+
if (
45+
isPlainObject(source[key]) &&
46+
// Avoid prototype pollution
47+
Object.prototype.hasOwnProperty.call(target, key) &&
48+
isPlainObject(target[key])
49+
) {
5050
// Since `output` is a clone of `target` and we have narrowed `target` in this block we can cast to the same type.
5151
(output as Record<keyof any, unknown>)[key] = deepmerge(target[key], source[key], options);
5252
} else if (options.clone) {

0 commit comments

Comments
 (0)