From dde3e2e7421858c7cd0c246cd31bfb7d896d4aec Mon Sep 17 00:00:00 2001 From: bcoe Date: Thu, 12 Mar 2020 12:03:37 -0700 Subject: [PATCH 1/2] fix: __proto__ will now be replaced with ___proto___ in parse --- package.json | 2 +- test/yargs.js | 31 +++++++++++++++++++++++++++++++ yargs.js | 11 ++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f1e99cda4..10ff93559 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^18.1.0" + "yargs-parser": "^18.1.1-beta.0" }, "devDependencies": { "c8": "^7.0.0", diff --git a/test/yargs.js b/test/yargs.js index 809fb1155..e999f0ef7 100644 --- a/test/yargs.js +++ b/test/yargs.js @@ -2500,4 +2500,35 @@ describe('yargs dsl tests', () => { }) }) }) + + // See: https://github.com/nodejs/node/issues/31951 + describe('should not pollute the prototype', () => { + it('does not pollute, when .parse() is called', function () { + yargs.parse(['-f.__proto__.foo', '99', '-x.y.__proto__.bar', '100', '--__proto__', '200']) + Object.keys({}.__proto__).length.should.equal(0) // eslint-disable-line + expect({}.foo).to.equal(undefined) + expect({}.bar).to.equal(undefined) + }) + + it('does not pollute, when .argv is called', function () { + yargs(['-f.__proto__.foo', '99', '-x.y.__proto__.bar', '100', '--__proto__', '200']).argv // eslint-disable-line + Object.keys({}.__proto__).length.should.equal(0) // eslint-disable-line + expect({}.foo).to.equal(undefined) + expect({}.bar).to.equal(undefined) + }) + + // TODO(bcoe): due to replacement of __proto__ with ___proto___ parser + // hints are not properly applied, we should move to an alternate approach + // in the future: + it('does not pollute, when options are set', function () { + yargs + .option('__proto__', { + describe: 'pollute pollute', + nargs: 33 + }) + .default('__proto__', { hello: 'world' }) + .parse(['--foo']) + Object.keys({}.__proto__).length.should.equal(0) // eslint-disable-line + }) + }) }) diff --git a/yargs.js b/yargs.js index 92474737e..aadfa9234 100644 --- a/yargs.js +++ b/yargs.js @@ -259,6 +259,7 @@ function Yargs (processArgs, cwd, parentRequire) { function populateParserHintArray (type, keys, value) { keys = [].concat(keys) keys.forEach((key) => { + key = sanitizeKey(key) options[type].push(key) }) } @@ -314,8 +315,8 @@ function Yargs (processArgs, cwd, parentRequire) { function populateParserHintObject (builder, isArray, type, key, value) { if (Array.isArray(key)) { + const temp = Object.create(null) // an array of keys with one value ['x', 'y', 'z'], function parse () {} - const temp = {} key.forEach((k) => { temp[k] = value }) @@ -326,6 +327,7 @@ function Yargs (processArgs, cwd, parentRequire) { builder(k, key[k]) }) } else { + key = sanitizeKey(key) // a single key value pair 'x', parse() {} if (isArray) { options[type][key] = (options[type][key] || []).concat(value) @@ -335,6 +337,13 @@ function Yargs (processArgs, cwd, parentRequire) { } } + // TODO(bcoe): in future major versions move more objects towards + // Object.create(null): + function sanitizeKey (key) { + if (key === '__proto__') return '___proto___' + return key + } + function deleteFromParserHintObject (optionKey) { // delete from all parsing hints: // boolean, array, key, alias, etc. From a1193a350b23a8bee2297ac48c248efc3fca5d3a Mon Sep 17 00:00:00 2001 From: bcoe Date: Mon, 16 Mar 2020 00:24:23 -0700 Subject: [PATCH 2/2] chore: update yargs-parser --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 10ff93559..f7740d83e 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^18.1.1-beta.0" + "yargs-parser": "^18.1.1" }, "devDependencies": { "c8": "^7.0.0",