From 47742078426f0e4e02aa988062b5fb0fa61182b9 Mon Sep 17 00:00:00 2001
From: Blaine Bublitz <blaine.bublitz@gmail.com>
Date: Thu, 21 May 2020 17:29:58 -0700
Subject: [PATCH 1/5] fix: back-porting prototype fixes for *really* old
 version (#271)

---
 index.js                  | 68 ++++++++++++++++++---------------------
 package.json              |  3 +-
 test/fixtures/config.json | 11 ++++++-
 test/yargs-parser.js      | 28 ++++++++++++++++
 4 files changed, 71 insertions(+), 39 deletions(-)

diff --git a/index.js b/index.js
index b71faf58..25110c56 100644
--- a/index.js
+++ b/index.js
@@ -2,14 +2,15 @@ var camelCase = require('camelcase')
 var path = require('path')
 var tokenizeArgString = require('./lib/tokenize-arg-string')
 var util = require('util')
+var assign = require('object.assign')
 
 function parse (args, opts) {
-  if (!opts) opts = {}
+  if (!opts) opts = Object.create(null)
   // allow a string argument to be passed in rather
   // than an argv array.
   args = tokenizeArgString(args)
   // aliases might have transitive relationships, normalize this.
-  var aliases = combineAliases(opts.alias || {})
+  var aliases = combineAliases(opts.alias || Object.create(null))
   var configuration = assign({
     'short-option-groups': true,
     'camel-case-expansion': true,
@@ -19,27 +20,27 @@ function parse (args, opts) {
     'duplicate-arguments-array': true,
     'flatten-duplicate-arrays': true
   }, opts.configuration)
-  var defaults = opts.default || {}
+  var defaults = opts.default || Object.create(null)
   var configObjects = opts.configObjects || []
   var envPrefix = opts.envPrefix
-  var newAliases = {}
+  var newAliases = Object.create(null)
   // allow a i18n handler to be passed in, default to a fake one (util.format).
   var __ = opts.__ || function (str) {
     return util.format.apply(util, Array.prototype.slice.call(arguments))
   }
   var error = null
   var flags = {
-    aliases: {},
-    arrays: {},
-    bools: {},
-    strings: {},
-    numbers: {},
-    counts: {},
-    normalize: {},
-    configs: {},
-    defaulted: {},
-    nargs: {},
-    coercions: {}
+    aliases: Object.create(null),
+    arrays: Object.create(null),
+    bools: Object.create(null),
+    strings: Object.create(null),
+    numbers: Object.create(null),
+    counts: Object.create(null),
+    normalize: Object.create(null),
+    configs: Object.create(null),
+    defaulted: Object.create(null),
+    nargs: Object.create(null),
+    coercions: Object.create(null)
   }
   var negative = /^-[0-9]+(\.[0-9]+)?/
 
@@ -67,11 +68,11 @@ function parse (args, opts) {
     flags.normalize[key] = true
   })
 
-  Object.keys(opts.narg || {}).forEach(function (k) {
+  Object.keys(opts.narg || Object.create(null)).forEach(function (k) {
     flags.nargs[k] = opts.narg[k]
   })
 
-  Object.keys(opts.coerce || {}).forEach(function (k) {
+  Object.keys(opts.coerce || Object.create(null)).forEach(function (k) {
     flags.coercions[k] = opts.coerce[k]
   })
 
@@ -80,7 +81,7 @@ function parse (args, opts) {
       flags.configs[key] = true
     })
   } else {
-    Object.keys(opts.config || {}).forEach(function (k) {
+    Object.keys(opts.config || Object.create(null)).forEach(function (k) {
       flags.configs[k] = opts.config[k]
     })
   }
@@ -417,7 +418,7 @@ function parse (args, opts) {
   // set args from config.json file, this should be
   // applied last so that defaults can be applied.
   function setConfig (argv) {
-    var configLookup = {}
+    var configLookup = Object.create(null)
 
     // expand defaults/aliases, in-case any happen to reference
     // the config.json file.
@@ -537,7 +538,7 @@ function parse (args, opts) {
     if (!configuration['dot-notation']) keys = [keys.join('.')]
 
     keys.slice(0, -1).forEach(function (key) {
-      o = (o[key] || {})
+      o = (o[key] || Object.create(null))
     })
 
     var key = keys[keys.length - 1]
@@ -551,8 +552,10 @@ function parse (args, opts) {
 
     if (!configuration['dot-notation']) keys = [keys.join('.')]
 
+    keys = keys.map(sanitizeKey)
+
     keys.slice(0, -1).forEach(function (key) {
-      if (o[key] === undefined) o[key] = {}
+      if (o[key] === undefined) o[key] = Object.create(null)
       o = o[key]
     })
 
@@ -584,7 +587,7 @@ function parse (args, opts) {
   // extend the aliases list with inferred aliases.
   function extendAliases () {
     Array.prototype.slice.call(arguments).forEach(function (obj) {
-      Object.keys(obj || {}).forEach(function (key) {
+      Object.keys(obj || Object.create(null)).forEach(function (key) {
         // short-circuit if we've already added a key
         // to the aliases array, for example it might
         // exist in both 'opts.default' and 'opts.key'.
@@ -681,7 +684,7 @@ function parse (args, opts) {
 function combineAliases (aliases) {
   var aliasArrays = []
   var change = true
-  var combined = {}
+  var combined = Object.create(null)
 
   // turn alias lookup hash {key: ['alias1', 'alias2']} into
   // a simple array ['key', 'alias1', 'alias2']
@@ -723,20 +726,6 @@ function combineAliases (aliases) {
   return combined
 }
 
-function assign (defaults, configuration) {
-  var o = {}
-  configuration = configuration || {}
-
-  Object.keys(defaults).forEach(function (k) {
-    o[k] = defaults[k]
-  })
-  Object.keys(configuration).forEach(function (k) {
-    o[k] = configuration[k]
-  })
-
-  return o
-}
-
 // this function should only be called when a count is given as an arg
 // it is NOT called to set a default value
 // thus we can start the count at 1 instead of 0
@@ -744,6 +733,11 @@ function increment (orig) {
   return orig !== undefined ? orig + 1 : 1
 }
 
+function sanitizeKey (key) {
+  if (key === '__proto__') return '___proto___'
+  return key
+}
+
 function Parser (args, opts) {
   var result = parse(args.slice(), opts)
 
diff --git a/package.json b/package.json
index d025a7ef..96af5496 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,8 @@
     "standard-version": "^4.0.0"
   },
   "dependencies": {
-    "camelcase": "^3.0.0"
+    "camelcase": "^3.0.0",
+    "object.assign": "^4.1.0"
   },
   "files": [
     "lib",
diff --git a/test/fixtures/config.json b/test/fixtures/config.json
index 43376463..f8918f61 100644
--- a/test/fixtures/config.json
+++ b/test/fixtures/config.json
@@ -3,5 +3,14 @@
     "z": 55,
     "foo": "baz",
     "version": "1.0.2",
-    "truthy": true
+    "truthy": true,
+    "toString": "method name",
+    "__proto__": {
+        "aaa": 99
+    },
+    "bar": {
+        "__proto__": {
+            "bbb": 100
+        }
+    }
 }
diff --git a/test/yargs-parser.js b/test/yargs-parser.js
index 5b59c615..4826b919 100644
--- a/test/yargs-parser.js
+++ b/test/yargs-parser.js
@@ -410,6 +410,26 @@ describe('yargs-parser', function () {
   describe('config', function () {
     var jsonPath = path.resolve(__dirname, './fixtures/config.json')
 
+    // Patching for https://snyk.io/vuln/SNYK-JS-YARGSPARSER-560381
+    it('should not pollute the prototype', function () {
+      const argv = parser(['--foo', 'bar'], {
+        alias: {
+          z: 'zoom'
+        },
+        default: {
+          settings: jsonPath
+        },
+        config: 'settings'
+      })
+
+      argv.should.have.property('herp', 'derp')
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('foo').and.deep.equal('bar')
+
+      expect({}.bbb).to.equal(undefined)
+      expect({}.aaa).to.equal(undefined)
+    })
+
     // See: https://github.com/chevex/yargs/issues/12
     it('should load options and values from default config if specified', function () {
       var argv = parser([ '--foo', 'bar' ], {
@@ -2375,4 +2395,12 @@ describe('yargs-parser', function () {
     })
     argv.a.should.deep.equal(['a.txt', 'b.txt'])
   })
+
+  // Patching for https://snyk.io/vuln/SNYK-JS-YARGSPARSER-560381
+  it('should not pollute the prototype', function () {
+    parser(['-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)
+  })
 })

From ee15863f7c62418c4fc92b64c3488778c46833dc Mon Sep 17 00:00:00 2001
From: bcoe <bencoe@google.com>
Date: Thu, 21 May 2020 17:32:44 -0700
Subject: [PATCH 2/5] chore: push new package version

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 96af5496..60a8df01 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yargs-parser",
-  "version": "5.0.0",
+  "version": "5.0.0-security.0",
   "description": "the mighty option parser used by yargs",
   "main": "index.js",
   "scripts": {

From e93a345e1e585ba5df97c1da438673e7f2e8909b Mon Sep 17 00:00:00 2001
From: "Benjamin E. Coe" <bencoe@google.com>
Date: Wed, 10 Mar 2021 11:07:39 -0800
Subject: [PATCH 3/5] chore: mark release in commit history (#361)


From 1c417bd0b42b09c475ee881e36d292af4fa2cc36 Mon Sep 17 00:00:00 2001
From: "Benjamin E. Coe" <bencoe@google.com>
Date: Wed, 10 Mar 2021 11:14:27 -0800
Subject: [PATCH 4/5] fix(security): address GHSA-p9pc-299p-vxgp (#362)

Update release automation to allow for back ports.
---
 .github/workflows/release-please.yml | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 .github/workflows/release-please.yml

diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml
new file mode 100644
index 00000000..757c171a
--- /dev/null
+++ b/.github/workflows/release-please.yml
@@ -0,0 +1,15 @@
+on:
+   push:
+     branches:
+       - v5.x.x
+name: release-please
+jobs:
+  release-please:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: google-github-actions/release-please-action@v2
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          release-type: node
+          package-name: yargs-parser
+          default-branch: v5.x.x

From eab6c039888bd5d51f33dda7a98808564acfa938 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 10 Mar 2021 11:16:06 -0800
Subject: [PATCH 5/5] chore: release 5.0.1 (#363)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
 CHANGELOG.md | 7 +++++++
 package.json | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd060f3c..727a83f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,13 @@ All notable changes to this project will be documented in this file. See [standa
 
 
 <a name="4.2.1"></a>
+### [5.0.1](https://www.github.com/yargs/yargs-parser/compare/v5.0.0...v5.0.1) (2021-03-10)
+
+
+### Bug Fixes
+
+* **security:** address GHSA-p9pc-299p-vxgp ([#362](https://www.github.com/yargs/yargs-parser/issues/362)) ([1c417bd](https://www.github.com/yargs/yargs-parser/commit/1c417bd0b42b09c475ee881e36d292af4fa2cc36))
+
 ## [4.2.1](https://github.com/yargs/yargs-parser/compare/v4.2.0...v4.2.1) (2017-01-02)
 
 
diff --git a/package.json b/package.json
index 60a8df01..90c1aa08 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yargs-parser",
-  "version": "5.0.0-security.0",
+  "version": "5.0.1",
   "description": "the mighty option parser used by yargs",
   "main": "index.js",
   "scripts": {