CVE-2023-6293: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') (CWE-1321)
value: Prototype Pollution in GitHub repository robinbuschmann/sequelize-typescript prior to 2.1.6.
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: 7.1
Published: 2023-11-24T20:15Z
Repository: https://github.com/robinbuschmann/sequelize-typescript
Language: TypeScript
Files changed: src/shared/object.ts, test/specs/utils/object.spec.ts
Commit date: 2023-11-24 20:36:06 +0100
Commit message: fix: deny modifying the object prototype (#1698)


Diff: diff --git a/src/shared/object.ts b/src/shared/object.ts
index ac78339..768fd8b 100644
--- a/src/shared/object.ts
+++ b/src/shared/object.ts
@@ -12,11 +12,14 @@ export function deepAssign<T, S1, S2, S3>(
 export function deepAssign<T, S1, S2>(target: T, source1: S1, source2: S2): T & S1 & S2;
 export function deepAssign<T, S>(target: T, source: S): T & S;
 export function deepAssign<S>(target: {}, source: S): S;
 export function deepAssign(target: any, ...sources: any[]): any {
   sources.forEach((source) => {
-    Object.getOwnPropertyNames(source).forEach((key) => assign(key, target, source));
+    Object.getOwnPropertyNames(source).forEach(
+      (key) =>
+        !['__proto__', 'constructor', 'prototype'].includes(key) && assign(key, target, source)
+    );
     /* istanbul ignore next */
     if (Object.getOwnPropertySymbols) {
       Object.getOwnPropertySymbols(source).forEach((key) => assign(key, target, source));
     }
   });
diff --git a/test/specs/utils/object.spec.ts b/test/specs/utils/object.spec.ts
index 5a6289f..7e8f475 100644
--- a/test/specs/utils/object.spec.ts
+++ b/test/specs/utils/object.spec.ts
@@ -1,7 +1,8 @@
 import { expect } from 'chai';
 import { deepAssign } from '../../../src/shared/object';
+import { addScopeOptions } from '../../../src/scopes/scope-service';
 
 describe('utils', () => {
   describe('object', () => {
     describe('deepAssign', () => {
       const childSourceF = {};
@@ -107,10 +108,18 @@ describe('utils', () => {
         const copy = deepAssign({}, { test: new Test() });
 
         expect(copy.test).to.have.property('protoFn').that.is.a('function');
       });
 
+      it('ignore prototype property', () => {
+        const BAD_JSON = JSON.parse('{"__proto__":{"polluted":true}}');
+        const empty_scope = {};
+
+        addScopeOptions(empty_scope, BAD_JSON);
+        expect(empty_scope).not.to.have.property('polluted');
+      });
+
       if (Object.getOwnPropertySymbols) {
         it('should copy symbol based objects', () => {
           const symbol = Symbol('test');
           const value = 'test';
           const copy = deepAssign({}, { [symbol]: value });

Vulnerable code:     Object.getOwnPropertyNames(source).forEach((key) => assign(key, target, source));
Fixed code:     Object.getOwnPropertyNames(source).forEach(
      (key) =>
        !['__proto__', 'constructor', 'prototype'].includes(key) && assign(key, target, source)
    );
import { addScopeOptions } from '../../../src/scopes/scope-service';
      it('ignore prototype property', () => {
        const BAD_JSON = JSON.parse('{"__proto__":{"polluted":true}}');
        const empty_scope = {};

        addScopeOptions(empty_scope, BAD_JSON);
        expect(empty_scope).not.to.have.property('polluted');
      });