diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 05f06b89..a6cb9100 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -93,6 +93,15 @@ export interface ServiceClientConstructor { service: ServiceDefinition; } +/** + * Returns true, if given key is included in the blacklisted + * keys. + * @param key key for check, string. + */ +function isPrototypePolluted(key: string): Boolean { + return ['__proto__', 'prototype', 'constructor'].includes(key); +} + /** * Creates a constructor for a client with the given methods, as specified in * the methods argument. The resulting class will have an instance method for @@ -122,7 +131,7 @@ export function makeClientConstructor( } Object.keys(methods).forEach((name) => { - if (name === '__proto__') { + if (isPrototypePolluted(name)) { return; } const attrs = methods[name]; @@ -155,7 +164,7 @@ export function makeClientConstructor( ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method Object.assign(ServiceClientImpl.prototype[name], attrs); - if (attrs.originalName && attrs.originalName !== '__proto__') { + if (attrs.originalName && !isPrototypePolluted(attrs.originalName)) { ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[name]; } @@ -204,7 +213,7 @@ export function loadPackageDefinition( if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) { const service = packageDef[serviceFqn]; const nameComponents = serviceFqn.split('.'); - if (nameComponents.some(comp => comp === '__proto__')) { + if (nameComponents.some((comp: string) => isPrototypePolluted(comp))) { continue; } const serviceName = nameComponents[nameComponents.length - 1]; diff --git a/packages/grpc-js/test/test-prototype-pollution.ts b/packages/grpc-js/test/test-prototype-pollution.ts index 12092608..6dc4b293 100644 --- a/packages/grpc-js/test/test-prototype-pollution.ts +++ b/packages/grpc-js/test/test-prototype-pollution.ts @@ -24,4 +24,8 @@ describe('loadPackageDefinition', () => { loadPackageDefinition({'__proto__.polluted': true} as any); assert.notStrictEqual(({} as any).polluted, true); }); + it('Should not allow prototype pollution #2', () => { + loadPackageDefinition({'constructor.prototype.polluted': true} as any); + assert.notStrictEqual(({} as any).polluted, true); + }); }); diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index d0bfd522..2514f0bd 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit d0bfd5221182da1a7cc280f3337b5e41a89539cf +Subproject commit 2514f0bd7da7e2af1bed4c5d1b84f031c4d12c10 diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 7dddbff0..86f45dc3 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.9.1", + "version": "1.10.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/",