Merge pull request #1654 from 418sec/1-npm-grpc

Security Fix for Prototype Pollution - huntr.dev
This commit is contained in:
Michael Lumish 2021-01-07 12:54:54 -08:00 committed by GitHub
commit fe4bd2641a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 18 additions and 5 deletions

View File

@ -93,6 +93,15 @@ export interface ServiceClientConstructor {
service: ServiceDefinition; 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 * 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 * the methods argument. The resulting class will have an instance method for
@ -122,7 +131,7 @@ export function makeClientConstructor(
} }
Object.keys(methods).forEach((name) => { Object.keys(methods).forEach((name) => {
if (name === '__proto__') { if (isPrototypePolluted(name)) {
return; return;
} }
const attrs = methods[name]; const attrs = methods[name];
@ -155,7 +164,7 @@ export function makeClientConstructor(
ServiceClientImpl.prototype[name] = methodFunc; ServiceClientImpl.prototype[name] = methodFunc;
// Associate all provided attributes with the method // Associate all provided attributes with the method
Object.assign(ServiceClientImpl.prototype[name], attrs); Object.assign(ServiceClientImpl.prototype[name], attrs);
if (attrs.originalName && attrs.originalName !== '__proto__') { if (attrs.originalName && !isPrototypePolluted(attrs.originalName)) {
ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[attrs.originalName] =
ServiceClientImpl.prototype[name]; ServiceClientImpl.prototype[name];
} }
@ -204,7 +213,7 @@ export function loadPackageDefinition(
if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) { if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) {
const service = packageDef[serviceFqn]; const service = packageDef[serviceFqn];
const nameComponents = serviceFqn.split('.'); const nameComponents = serviceFqn.split('.');
if (nameComponents.some(comp => comp === '__proto__')) { if (nameComponents.some((comp: string) => isPrototypePolluted(comp))) {
continue; continue;
} }
const serviceName = nameComponents[nameComponents.length - 1]; const serviceName = nameComponents[nameComponents.length - 1];

View File

@ -24,4 +24,8 @@ describe('loadPackageDefinition', () => {
loadPackageDefinition({'__proto__.polluted': true} as any); loadPackageDefinition({'__proto__.polluted': true} as any);
assert.notStrictEqual(({} as any).polluted, true); 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);
});
}); });

@ -1 +1 @@
Subproject commit d0bfd5221182da1a7cc280f3337b5e41a89539cf Subproject commit 2514f0bd7da7e2af1bed4c5d1b84f031c4d12c10

View File

@ -1,6 +1,6 @@
{ {
"name": "grpc-tools", "name": "grpc-tools",
"version": "1.9.1", "version": "1.10.0",
"author": "Google Inc.", "author": "Google Inc.",
"description": "Tools for developing with gRPC on Node.js", "description": "Tools for developing with gRPC on Node.js",
"homepage": "https://grpc.io/", "homepage": "https://grpc.io/",