CVE-2020-7637: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') (CWE-1321)
value: class-transformer before 0.3.1 allow attackers to perform Prototype Pollution. The classToPlainFromExist function could be tricked into adding or modifying properties of Object.prototype using a __proto__ payload.
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: 5.3
Published: 2020-04-06T13:15Z
Repository: https://github.com/typestack/class-transformer
Language: TypeScript
Files changed: src/TransformOperationExecutor.ts, test/functional/basic-functionality.spec.ts
Commit date: 2020-07-20 19:08:51 -0300
Commit message: Fix prototype pollution vulnerabilities

Diff: diff --git a/src/TransformOperationExecutor.ts b/src/TransformOperationExecutor.ts
index d76815e..6dd31ab 100644
--- a/src/TransformOperationExecutor.ts
+++ b/src/TransformOperationExecutor.ts
@@ -143,10 +143,14 @@ export class TransformOperationExecutor {
                 }
             }
 
             // traverse over keys
             for (const key of keys) {
+                if (key === '__proto__' || key === 'constructor') {
+                    continue;
+                }
+
                 const valueKey = key;
                 let newValueKey = key, propertyName = key;
                 if (!this.options.ignoreDecorators && targetType) {
                     if (this.transformationType === TransformationType.PLAIN_TO_CLASS) {
                         const exposeMetadata = defaultMetadataStorage.findExposeMetadataByCustomName((targetType as Function), key);
diff --git a/test/functional/basic-functionality.spec.ts b/test/functional/basic-functionality.spec.ts
index 75b9293..7f96086 100644
--- a/test/functional/basic-functionality.spec.ts
+++ b/test/functional/basic-functionality.spec.ts
@@ -1747,10 +1747,24 @@ describe("basic functionality", () => {
 
         const transformedClass = plainToClass(TestClass, obj);
         expect(transformedClass).toBeInstanceOf(TestClass);
     });
 
+    it('should not pollute the prototype with a `__proto__` property',() => {
+        const object = JSON.parse('{"__proto__": { "admin": true }}');
+        const plainObject = {};
+        classToPlainFromExist(object, plainObject);
+        expect((plainObject as any).admin).toEqual(undefined);
+    });
+
+    it('should not pollute the prototype with a `constructor.prototype` property',  () => {
+        const object = JSON.parse('{"constructor": { "prototype": { "admin": true }}}');
+        const plainObject = {};
+        classToPlainFromExist(object, plainObject);
+        expect((plainObject as any).admin).toEqual(undefined);
+    });
+
     it("should default union types where the plain type is an array to an array result", () => {
         class User {
             name: string;
         }
 

Fixed code:                 if (key === '__proto__' || key === 'constructor') {
                    continue;
                }

    it('should not pollute the prototype with a `__proto__` property',() => {
        const object = JSON.parse('{"__proto__": { "admin": true }}');
        const plainObject = {};
        classToPlainFromExist(object, plainObject);
        expect((plainObject as any).admin).toEqual(undefined);
    });

    it('should not pollute the prototype with a `constructor.prototype` property',  () => {
        const object = JSON.parse('{"constructor": { "prototype": { "admin": true }}}');
        const plainObject = {};
        classToPlainFromExist(object, plainObject);
        expect((plainObject as any).admin).toEqual(undefined);
    });