VYPR
Moderate severityNVD Advisory· Published Oct 20, 2020· Updated Sep 17, 2024

Prototype Pollution

CVE-2020-7748

Description

Prototype pollution in @tsed/core's deepExtend allows attackers to overwrite Object prototype, leading to potential DoS or RCE.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Prototype pollution in @tsed/core's deepExtend allows attackers to overwrite Object prototype, leading to potential DoS or RCE.

The vulnerability is a prototype pollution flaw in the deepExtend function of @tsed/core, a utility library for the Ts.ED framework. The function does not properly restrict the modification of object prototypes, allowing an attacker to inject properties into the global Object.prototype [1][4].

Exploitation occurs when user input is passed to deepExtend without sanitization. An attacker can craft a malicious object containing __proto__ or constructor.prototype properties, which when merged pollutes the prototype chain. This can be triggered via application endpoints that accept JSON or other serialized input that eventually reaches deepExtend [2][4].

Once the prototype is polluted, all objects inherit the injected properties, potentially causing denial of service via exceptions or altering application behavior. In severe cases, this can lead to remote code execution if the polluted properties are used in security-sensitive operations [4].

The fix was released in version 5.65.7, which uses an objectKeys function to prevent prototype properties from being overwritten [2]. Users should upgrade to the latest version. The vulnerability is listed in Snyk and other databases [1][4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@tsed/corenpm
< 5.65.75.65.7

Affected products

2

Patches

1
1395773ddac3

fix: Use objectKeys to prevent prototype pollution

https://github.com/TypedProject/tsedRomain LenzottiOct 18, 2020via ghsa
9 files changed · +28 31
  • packages/common/src/converters/components/MapConverter.ts+2 1 modified
    @@ -1,3 +1,4 @@
    +import {objectKeys} from "@tsed/core";
     import {Converter} from "../decorators/converter";
     import {IConverter, IDeserializer, ISerializer} from "../interfaces/index";
     
    @@ -19,7 +20,7 @@ export class MapConverter implements IConverter {
       deserialize<T>(data: any, target: any, baseType: T, deserializer: IDeserializer): Map<string, T> {
         const obj = new Map<string, T>();
     
    -    Object.keys(data).forEach((key) => {
    +    objectKeys(data).forEach((key) => {
           obj.set(key, deserializer(data[key], baseType) as T);
         });
     
    
  • packages/common/src/converters/components/SetConverter.ts+2 1 modified
    @@ -1,3 +1,4 @@
    +import {objectKeys} from "@tsed/core";
     import {Converter} from "../decorators/converter";
     import {IConverter, IDeserializer, ISerializer} from "../interfaces/index";
     
    @@ -19,7 +20,7 @@ export class SetConverter implements IConverter {
       deserialize<T>(data: any, target: any, baseType: T, deserializer: IDeserializer): Set<T> {
         const obj = new Set<T>();
     
    -    Object.keys(data).forEach((key) => {
    +    objectKeys(data).forEach((key) => {
           obj.add(deserializer(data[key], baseType) as T);
         });
     
    
  • packages/common/src/converters/services/ConverterService.ts+3 3 modified
    @@ -1,4 +1,4 @@
    -import {getClass, isArrayOrArrayClass, isEmpty, isPrimitiveOrPrimitiveClass, Metadata, Type} from "@tsed/core";
    +import {getClass, isArrayOrArrayClass, isEmpty, isPrimitiveOrPrimitiveClass, Metadata, objectKeys, Type} from "@tsed/core";
     import {Configuration, Injectable, InjectorService} from "@tsed/di";
     import {IConverterSettings} from "../../config/interfaces/IConverterSettings";
     import {PropertyMetadata} from "../../mvc/models/PropertyMetadata";
    @@ -101,7 +101,7 @@ export class ConverterService {
     
         const plainObject: any = {};
         const properties = PropertyMetadata.getProperties(options.type || obj, {withIgnoredProps});
    -    const keys = properties.size ? Array.from(properties.keys()) : Object.keys(obj);
    +    const keys = properties.size ? Array.from(properties.keys()) : objectKeys(obj);
     
         keys.forEach((propertyKey) => {
           if (typeof obj[propertyKey] !== "function") {
    @@ -179,7 +179,7 @@ export class ConverterService {
         const instance = new targetType();
         const properties = PropertyMetadata.getProperties(targetType);
     
    -    Object.keys(obj).forEach((propertyName: string) => {
    +    objectKeys(obj).forEach((propertyName: string) => {
           const propertyMetadata = ConverterService.getPropertyMetadata(properties, propertyName);
     
           return this.convertProperty(obj, instance, propertyName, propertyMetadata, options);
    
  • packages/core/src/utils/cleanObject.ts+13 11 modified
    @@ -1,17 +1,19 @@
    +import {isProtectedKey} from "./isProtectedKey";
     /**
      * Remove undefined value
      * @param obj
      */
    -
     export function cleanObject(obj: any): any {
    -  return Object.entries(obj).reduce(
    -    (obj, [key, value]) =>
    -      value === undefined
    -        ? obj
    -        : {
    -            ...obj,
    -            [key]: value
    -          },
    -    {}
    -  );
    +  return Object.entries(obj).reduce((obj, [key, value]) => {
    +    if (isProtectedKey(key)) {
    +      return obj;
    +    }
    +
    +    return value === undefined
    +      ? obj
    +      : {
    +          ...obj,
    +          [key]: value
    +        };
    +  }, {});
     }
    
  • packages/json-mapper/src/components/MapMapper.ts+2 1 modified
    @@ -1,3 +1,4 @@
    +import {objectKeys} from "@tsed/core";
     import {JsonMapper} from "../decorators/jsonMapper";
     import {JsonMapperCtx, JsonMapperMethods} from "../interfaces/JsonMapperMethods";
     
    @@ -12,7 +13,7 @@ export class MapMapper implements JsonMapperMethods {
       deserialize<T = any, C = Map<string, T>>(data: {[key: string]: any}, ctx: JsonMapperCtx<T, C>): Map<string, T> {
         const obj = new Map<string, T>();
     
    -    Object.keys(data).forEach((key) => {
    +    objectKeys(data).forEach((key) => {
           obj.set(key, ctx.next(data[key]) as T);
         });
     
    
  • packages/json-mapper/src/components/SetMapper.ts+2 1 modified
    @@ -1,3 +1,4 @@
    +import {objectKeys} from "@tsed/core";
     import {JsonMapper} from "../decorators/jsonMapper";
     import {JsonMapperCtx, JsonMapperMethods} from "../interfaces/JsonMapperMethods";
     
    @@ -12,7 +13,7 @@ export class SetMapper implements JsonMapperMethods {
       deserialize<T>(data: any, ctx: JsonMapperCtx): Set<T> {
         const obj = new Set<T>();
     
    -    Object.keys(data).forEach((key) => {
    +    objectKeys(data).forEach((key) => {
           obj.add(ctx.next(data[key]));
         });
     
    
  • packages/json-mapper/src/utils/deserialize.ts+2 2 modified
    @@ -1,4 +1,4 @@
    -import {isArray, isEmpty, isNil, MetadataTypes, nameOf, Type} from "@tsed/core";
    +import {isArray, isEmpty, isNil, MetadataTypes, nameOf, objectKeys, Type} from "@tsed/core";
     import {getPropertiesStores, JsonEntityStore, JsonHookContext, JsonSchema} from "@tsed/schema";
     import "../components";
     import {JsonMapperContext} from "../domain/JsonMapperContext";
    @@ -77,7 +77,7 @@ export function plainObjectToClass<T = any>(src: any, options: JsonDeserializerO
       const {type, store = JsonEntityStore.from(type), ...next} = options;
       const propertiesMap = getPropertiesStores(store);
     
    -  let keys = Object.keys(src);
    +  let keys = objectKeys(src);
       const additionalProperties = propertiesMap.size ? !!store.schema.get("additionalProperties") || options.additionalProperties : true;
       const out: any = new type(src);
     
    
  • packages/mongoose/src/utils/cleanProps.ts+0 8 removed
    @@ -1,8 +0,0 @@
    -export const cleanProps = (src: any) =>
    -  Object.keys(src).reduce((obj: any, k: any) => {
    -    if (src[k] !== undefined) {
    -      obj[k] = src[k];
    -    }
    -
    -    return obj;
    -  }, {});
    
  • packages/mongoose/src/utils/createSchema.ts+2 3 modified
    @@ -1,10 +1,9 @@
     import {ConverterService, IConverterOptions, JsonSchema, PropertyMetadata} from "@tsed/common";
    -import {getClass, Store, Type} from "@tsed/core";
    +import {cleanObject, getClass, Store, Type} from "@tsed/core";
     import * as mongoose from "mongoose";
     import {SchemaDefinition, SchemaTypeOpts} from "mongoose";
     import {MONGOOSE_SCHEMA} from "../constants";
     import {MongooseSchemaOptions} from "../interfaces";
    -import {cleanProps} from "./cleanProps";
     import {schemaOptions} from "./schemaOptions";
     
     const MONGOOSE_RESERVED_KEYS = ["_id"];
    @@ -132,7 +131,7 @@ export function createSchemaTypeOptions(propertyMetadata: PropertyMetadata): Sch
         schemaTypeOptions = {...schemaTypeOptions, type: getSchema(propertyMetadata.type)};
       }
     
    -  schemaTypeOptions = cleanProps({...schemaTypeOptions, ...rawMongooseSchema});
    +  schemaTypeOptions = cleanObject({...schemaTypeOptions, ...rawMongooseSchema});
     
       if (propertyMetadata.isCollection) {
         if (propertyMetadata.isArray) {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.