CVE-2023-36665: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') (CWE-1321)
value: "protobuf.js (aka protobufjs) 6.10.0 through 7.x before 7.2.5 allows Prototype Pollution, a different vulnerability than CVE-2022-25878. A user-controlled protobuf message can be used by an attacker to pollute the prototype of Object.prototype by adding and overwriting its data and functions. Exploitation can involve: (1) using the function parse to parse protobuf messages on the fly, (2) loading .proto files by using load/loadSync functions, or (3) providing untrusted input to the functions ReflectionObject.setParsedOption and util.setProperty.
CWE description: The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.
CVSS v3 base score: 9.8
Published: 2023-07-05T14:15Z
Repository: https://github.com/protobufjs/protobuf.js
Language: JavaScript
Files changed: src/util.js, tests/api_util.js
Commit date: 2023-06-23 15:46:03 -0700
Commit message: fix: do not let setProperty change the prototype (#1899)

* fix: do not let setProperty change the prototype

* test: add unit test
Diff: diff --git a/src/util.js b/src/util.js
index c39d33a..6c50899 100644
--- a/src/util.js
+++ b/src/util.js
@@ -174,11 +174,11 @@ util.decorateEnum = function decorateEnum(object) {
  * @returns {Object.<string,*>} Destination object
  */
 util.setProperty = function setProperty(dst, path, value) {
     function setProp(dst, path, value) {
         var part = path.shift();
-        if (part === "__proto__") {
+        if (part === "__proto__" || part === "prototype") {
           return dst;
         }
         if (path.length > 0) {
             dst[part] = setProp(dst[part] || {}, path, value);
         } else {
diff --git a/tests/api_util.js b/tests/api_util.js
index 7b6f50f..63da017 100644
--- a/tests/api_util.js
+++ b/tests/api_util.js
@@ -93,10 +93,19 @@ tape.test("util", function(test) {
         util.setProperty(o, 'prop.subprop.subsub', 6);
         test.same(o, {prop1: [5, 6], prop: {subprop: {subsub: [5, 6]}}}, "should convert to array nested property");
 
         util.setProperty(o, 'prop.subprop', { subsub2: 7});
         test.same(o, {prop1: [5, 6], prop: {subprop: [{subsub: [5,6]}, {subsub2: 7}]}}, "should convert nested properties to array");
+        
+        util.setProperty({}, "__proto__.test", "value");
+        test.is({}.test, undefined);
+
+        util.setProperty({}, "prototype.test", "value");
+        test.is({}.test, undefined);
+
+        util.setProperty({}, "constructor.prototype.test", "value");
+        test.is({}.test, undefined);
 
         test.end();
     });
 
     test.end();

Vulnerable code:         if (part === "__proto__") {
Fixed code:         if (part === "__proto__" || part === "prototype") {
        
        util.setProperty({}, "__proto__.test", "value");
        test.is({}.test, undefined);

        util.setProperty({}, "prototype.test", "value");
        test.is({}.test, undefined);

        util.setProperty({}, "constructor.prototype.test", "value");
        test.is({}.test, undefined);