From 4ab101aaf78cee0cee7e902e196e2dcde18f15e1 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 2 Oct 2024 08:46:34 +0100 Subject: [PATCH] [ML] [7.17] Potential prototype pollution vulnerability (#194538) Fixes potential prototype pollution vulnerability in `setNestedProperty` function. --- .../transform/common/utils/object_utils.test.ts | 12 +++++++++++- .../plugins/transform/common/utils/object_utils.ts | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/transform/common/utils/object_utils.test.ts b/x-pack/plugins/transform/common/utils/object_utils.test.ts index c99adf6b6d189..293a8ada7cbc5 100644 --- a/x-pack/plugins/transform/common/utils/object_utils.test.ts +++ b/x-pack/plugins/transform/common/utils/object_utils.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { getNestedProperty } from './object_utils'; +import { getNestedProperty, setNestedProperty } from './object_utils'; describe('object_utils', () => { test('getNestedProperty()', () => { @@ -67,5 +67,15 @@ describe('object_utils', () => { const test11 = getNestedProperty(falseyObj, 'the.other_nested.value'); expect(typeof test11).toBe('number'); expect(test11).toBe(0); + + expect(() => { + setNestedProperty(testObj, 'the.__proto__', 'update'); + }).toThrow('Invalid accessor'); + expect(() => { + setNestedProperty(testObj, 'the.prototype', 'update'); + }).toThrow('Invalid accessor'); + expect(() => { + setNestedProperty(testObj, 'the.constructor', 'update'); + }).toThrow('Invalid accessor'); }); }); diff --git a/x-pack/plugins/transform/common/utils/object_utils.ts b/x-pack/plugins/transform/common/utils/object_utils.ts index 605af48914360..3c4b3defe89db 100644 --- a/x-pack/plugins/transform/common/utils/object_utils.ts +++ b/x-pack/plugins/transform/common/utils/object_utils.ts @@ -34,9 +34,15 @@ export function getNestedProperty( return o; } +const INVALID_ACCESSORS = ['__proto__', 'prototype', 'constructor']; + export const setNestedProperty = (obj: Record, accessor: string, value: any) => { let ref = obj; const accessors = accessor.split('.'); + if (accessors.some((a) => INVALID_ACCESSORS.includes(a))) { + throw new Error('Invalid accessor'); + } + const len = accessors.length; for (let i = 0; i < len - 1; i++) { const attribute = accessors[i];