High severity8.3NVD Advisory· Published Jun 17, 2024· Updated Apr 15, 2026
CVE-2024-36577
CVE-2024-36577
Description
apphp js-object-resolver < 3.1.1 is vulnerable to Prototype Pollution via Module.setNestedProperty.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
@apphp/object-resolvernpm | < 3.1.1 | 3.1.1 |
Patches
17e347a26bf04Fix for prototype pollution vulnerability
2 files changed · +59 −7
dist/object-resolver.js+21 −6 modified@@ -241,20 +241,33 @@ const fetchLastNestedProperty = function (obj, path) { * @param {*} value - The value to set for the nested property. */ const setNestedProperty = function (obj, path, value) { - const keys = Array.isArray(path) ? path : path.split('.'); + let keys = path; let current = obj; + if (typeof keys === 'string') { + keys = keys.split('.'); + } + + if (!Array.isArray(keys)) { + throw new Error('Path must be a string or an array'); + } + for (let i = 0; i < keys.length; i++) { const key = keys[i]; + // Prevent prototype pollution + if (key === '__proto__' || key === 'constructor' || key === 'prototype') { + throw new Error('Invalid property key'); + } + // Check if the current property is an array and if the key has array notation const isArray = Array.isArray(current); const isArrayNotation = key.includes('[') && key.endsWith(']'); const isNumericKey = /^\d+$/.test(key.replace(/\[.*\]/, '')); if (isArray && isArrayNotation && isNumericKey) { const [arrayKey, indexKey] = key.split(/\[|\]/).filter(Boolean); - const index = parseInt(indexKey); + const index = parseInt(indexKey, 10); while (current[arrayKey].length <= index) { current[arrayKey].push(null); // Ensure the array is long enough @@ -264,16 +277,18 @@ const setNestedProperty = function (obj, path, value) { // Last key in the path, set the value current[arrayKey][index] = value; } else { - // Continue into the nested object - current = current[arrayKey][index] = current[arrayKey][index] || {}; + // Prevent undefined objects in the path + if (!current[arrayKey][index]) current[arrayKey][index] = {}; + current = current[arrayKey][index]; } } else { if (i === keys.length - 1) { // Last key in the path, set the value current[key] = value; } else { - // Continue into the nested object - current = current[key] = current[key] || {}; + // Prevent undefined objects in the path + if (!current[key]) current[key] = {}; + current = current[key]; } } }
tests/setNestedProperty.test.js+38 −1 modified@@ -1,8 +1,45 @@ const {setNestedProperty: setNestedPropertyTest} = require('../dist/object-resolver'); describe('Test function setNestedProperty', () => { + // Test cases for setNestedProperty + + let obj; + + beforeEach(() => { + obj = { + existing: { property: 'value' }, + arrayProperty: [{ nestedArray: 'nestedValue' }] + }; + }); + + test('Should throw an error when trying to modify __proto__', () => { + const obj = {}; + expect(() => setNestedPropertyTest(obj, '__proto__.polluted', 'yes')).toThrow('Invalid property key'); + }); + + test('Should throw an error for non-string and non-array path', () => { + expect(() => setNestedPropertyTest(obj, null, 'newValue')).toThrow('Path must be a string or an array'); + expect(() => setNestedPropertyTest(obj, 42, 'newValue')).toThrow('Path must be a string or an array'); + expect(() => setNestedPropertyTest(obj, {}, 'newValue')).toThrow('Path must be a string or an array'); + }); + + test('Should throw an error when trying to modify prototype', () => { + expect(() => setNestedPropertyTest(obj, 'prototype.polluted', 'yes')).toThrow('Invalid property key'); + }); + + test('Should throw an error when trying to modify constructor', () => { + expect(() => setNestedPropertyTest(obj, 'constructor.polluted', 'yes')).toThrow('Invalid property key'); + }); + + test('Sets a value at an existing index in an array', () => { + const obj = { + numbers: [1, 2, 3] + }; + + setNestedPropertyTest(obj, 'numbers.1', 99); + expect(obj.numbers[1]).toBe(99); + }); -// Test cases for setNestedProperty test('Should set a deeply nested property', () => { const obj = {}; setNestedPropertyTest(obj, 'user.profile.name', 'John Doe');
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.