CVE-2021-25912 (published 2021-02-02T19:15Z)

Prototype pollution vulnerability in 'dotty' versions 0.0.1 through 0.1.0 allows attackers to cause a denial of service and may lead to remote code execution.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-1321
cwe_name: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
description: The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.
extended_description: 
				By adding or modifying attributes of an object prototype, it is possible to create attributes that exist on every object, or replace critical attributes with malicious ones. This can be problematic if the product depends on existence or non-existence of certain attributes, or uses pre-defined attributes of object prototype (such as hasOwnProperty, toString or valueOf).
				This weakness is usually exploited by using a special attribute of objects called proto,  constructor or prototype. Such attributes give access to the object prototype. This weakness is often found in code that assigns object attributes based on user input, or merges or clones objects recursively.
			
			

Fix information:
repo_url: https://github.com/deoxxa/dotty
commit_details: repo_url: https://github.com/deoxxa/dotty
author: Michael Stramel
author_date: 2021-01-25 12:20:41-06:00
msg: Fix prototype pollution (#26)
repository: repo_url: https://github.com/deoxxa/dotty
repo_name: deoxxa/dotty
description: Access properties of nested objects using dot-path notation
repo_language: JavaScript
owner: deoxxa
file_changes: filename: index.html
change_type: ModificationType.MODIFY
diff: @@ -5,7 +5,7 @@
   <title>index.js</title>
   <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
-  <link rel="stylesheet" media="all" href="..\docco.css" />
+  <link rel="stylesheet" media="all" href="../docco.css" />
 </head>
 <body>
   <div id="container">

programming_language: HTML
filename: index.js
change_type: ModificationType.MODIFY
diff: @@ -13,7 +13,7 @@
 // Returns `true` if the path can be completely resolved, `false` otherwise.
 //
 
-var exists = module.exports.exists = function exists(object, path) {
+var exists = (module.exports.exists = function exists(object, path) {
   if (typeof path === "string") {
     path = path.split(".");
   }
@@ -35,19 +35,19 @@ var exists = module.exports.exists = function exists(object, path) {
   } else {
     return exists(object[key], path);
   }
-};
+});
 
 //
 // These arguments are the same as those for `exists`.
 //
 // The return value, however, is the property you're trying to access, or
 // `undefined` if it can't be found. This means you won't be able to tell
-// the difference between an unresolved path and an undefined property, so you 
+// the difference between an unresolved path and an undefined property, so you
 // should not use `get` to check for the existence of a property. Use `exists`
 // instead.
 //
 
-var get = module.exports.get = function get(object, path) {
+var get = (module.exports.get = function get(object, path) {
   if (typeof path === "string") {
     path = path.split(".");
   }
@@ -71,7 +71,7 @@ var get = module.exports.get = function get(object, path) {
   if (path.length) {
     return get(object[key], path);
   }
-};
+});
 
 //
 // Arguments are similar to `exists` and `get`, with the exception that path
@@ -85,7 +85,7 @@ var get = module.exports.get = function get(object, path) {
 // match. Action params are value, parent and key.
 //
 
-var search = module.exports.search = function search(object, path, action) {
+var search = (module.exports.search = function search(object, path, action) {
   if (typeof path === "string") {
     path = path.split(".");
   }
@@ -111,29 +111,41 @@ var search = module.exports.search = function search(object, path, action) {
   }
 
   if (path.length === 0) {
-    return Object.keys(object).filter(key.test.bind(key)).map(function(k) {
-      var value = object[k];
-      if(action){
-        action(value, object, k);
-      }
-      return value;
-    });
+    return Object.keys(object)
+      .filter(key.test.bind(key))
+      .map(function (k) {
+        var value = object[k];
+        if (action) {
+          action(value, object, k);
+        }
+        return value;
+      });
   } else {
-    return Array.prototype.concat.apply([], Object.keys(object).filter(key.test.bind(key)).map(function(k) { return search(object[k], path, action); }));
+    return Array.prototype.concat.apply(
+      [],
+      Object.keys(object)
+        .filter(key.test.bind(key))
+        .map(function (k) {
+          return search(object[k], path, action);
+        })
+    );
   }
-};
+});
 
 //
 // Perform a search and remove the matched keys.
 // The return value is the same object argument with modifications.
 //
 
-var removeSearch = module.exports.removeSearch = function removeSearch(object, path){
-  search(object, path, function(value, object, key){
+var removeSearch = (module.exports.removeSearch = function removeSearch(
+  object,
+  path
+) {
+  search(object, path, function (value, object, key) {
     delete object[key];
   });
   return object;
-};
+});
 
 //
 // The first two arguments for `put` are the same as `exists` and `get`.
@@ -147,7 +159,7 @@ var removeSearch = module.exports.removeSearch = function removeSearch(object, p
 // successfully, or `false` otherwise.
 //
 
-var put = module.exports.put = function put(object, path, value) {
+var put = (module.exports.put = function put(object, path, value) {
   if (typeof path === "string") {
     path = path.split(".");
   }
@@ -155,15 +167,14 @@ var put = module.exports.put = function put(object, path, value) {
   if (!(path instanceof Array) || path.length === 0) {
     return false;
   }
-  
+
   path = path.slice();
 
   var key = path.shift();
 
-  if (typeof object !== "object" || object === null) {
+  if (typeof object !== "object" || object === null || key === "__proto__") {
     return false;
   }
-
   if (path.length === 0) {
     object[key] = value;
   } else {
@@ -177,7 +188,7 @@ var put = module.exports.put = function put(object, path, value) {
 
     return put(object[key], path, value);
   }
-};
+});
 
 //
 // `remove` is like `put` in reverse!
@@ -186,7 +197,7 @@ var put = module.exports.put = function put(object, path, value) {
 // successfully, or `false` otherwise.
 //
 
-var remove = module.exports.remove = function remove(object, path, value) {
+var remove = (module.exports.remove = function remove(object, path, value) {
   if (typeof path === "string") {
     path = path.split(".");
   }
@@ -194,7 +205,7 @@ var remove = module.exports.remove = function remove(object, path, value) {
   if (!(path instanceof Array) || path.length === 0) {
     return false;
   }
-  
+
   path = path.slice();
 
   var key = path.shift();
@@ -214,7 +225,7 @@ var remove = module.exports.remove = function remove(object, path, value) {
   } else {
     return remove(object[key], path, value);
   }
-};
+});
 
 //
 // `deepKeys` creates a list of all possible key paths for a given object.
@@ -231,7 +242,11 @@ var remove = module.exports.remove = function remove(object, path, value) {
 // *Note: this will probably explode on recursive objects. Be careful.*
 //
 
-var deepKeys = module.exports.deepKeys = function deepKeys(object, options, prefix) {
+var deepKeys = (module.exports.deepKeys = function deepKeys(
+  object,
+  options,
+  prefix
+) {
   options = options || {};
 
   if (typeof prefix === "undefined") {
@@ -250,13 +265,21 @@ var deepKeys = module.exports.deepKeys = function deepKeys(object, options, pref
     }
 
     if (typeof object[k] === "object" && object[k] !== null) {
-      keys = keys.concat(deepKeys(object[k], {leavesOnly: options.leavesOnly}, prefix.concat([k])));
+      keys = keys.concat(
+        deepKeys(
+          object[k],
+          { leavesOnly: options.leavesOnly },
+          prefix.concat([k])
+        )
+      );
     }
   }
 
   if (options.asStrings) {
-    keys = keys.map(function(e) { return e.join("."); });
+    keys = keys.map(function (e) {
+      return e.join(".");
+    });
   }
 
   return keys;
-};
+});

programming_language: JavaScript
filename: package-lock.json
change_type: ModificationType.MODIFY
diff: @@ -22,11 +22,11 @@
       "integrity": "sha512-QcWBDnnGaT+rgC0wqynznXv0/4hd6nAFdWNs2fN4FvkH2yAnCYVeRU7GIZXNCeUQ955Lufq+TmZcSXiBa1cGQQ==",
       "dev": true,
       "requires": {
-        "commander": "2.14.1",
-        "fs-extra": "5.0.0",
-        "highlight.js": "9.12.0",
-        "marked": "0.3.16",
-        "underscore": "1.8.3"
+        "commander": ">= 0.5.2",
+        "fs-extra": ">= 0.6.0",
+        "highlight.js": ">= 8.0.x",
+        "marked": ">= 0.2.7",
+        "underscore": ">= 1.0.0"
       }
     },
     "eyes": {
@@ -41,9 +41,9 @@
       "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
       "dev": true,
       "requires": {
-        "graceful-fs": "4.1.11",
-        "jsonfile": "4.0.0",
-        "universalify": "0.1.1"
+        "graceful-fs": "^4.1.2",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
       }
     },
     "glob": {
@@ -52,10 +52,10 @@
       "integrity": "sha1-aVxQvdTi+1xdNwsJHziNNwfikac=",
       "dev": true,
       "requires": {
-        "graceful-fs": "3.0.11",
-        "inherits": "2.0.3",
-        "minimatch": "1.0.0",
-        "once": "1.4.0"
+        "graceful-fs": "^3.0.2",
+        "inherits": "2",
+        "minimatch": "^1.0.0",
+        "once": "^1.3.0"
       },
       "dependencies": {
         "graceful-fs": {
@@ -64,7 +64,7 @@
           "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=",
           "dev": true,
           "requires": {
-            "natives": "1.1.1"
+            "natives": "^1.1.0"
           }
         }
       }
@@ -93,7 +93,7 @@
       "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
       "dev": true,
       "requires": {
-        "graceful-fs": "4.1.11"
+        "graceful-fs": "^4.1.6"
       }
     },
     "lru-cache": {
@@ -114,8 +114,8 @@
       "integrity": "sha1-4N0hILSeG3JM6NcUxSCCKpQ4V20=",
       "dev": true,
       "requires": {
-        "lru-cache": "2.7.3",
-        "sigmund": "1.0.1"
+        "lru-cache": "2",
+        "sigmund": "~1.0.0"
       }
     },
     "natives": {
@@ -130,7 +130,7 @@
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
       "dev": true,
       "requires": {
-        "wrappy": "1.0.2"
+        "wrappy": "1"
       }
     },
     "sigmund": {
@@ -157,9 +157,9 @@
       "integrity": "sha1-4J6YjOWUygWgjXKrzKNOiNtVkTE=",
       "dev": true,
       "requires": {
-        "diff": "1.0.8",
-        "eyes": "0.1.8",
-        "glob": "4.0.6"
+        "diff": "~1.0.8",
+        "eyes": "~0.1.6",
+        "glob": "~4.0.6"
       }
     },
     "wrappy": {

programming_language: JavaScript
filename: exists-test.js
change_type: ModificationType.MODIFY
diff: @@ -1,62 +1,65 @@
 var dotty = require("../lib/index"),
-    vows = require("vows"),
-    assert = require("assert");
+  vows = require("vows"),
+  assert = require("assert");
 
-vows.describe("exists").addBatch({
-  "A simple path": {
-    "as a string": {
-      topic: dotty.exists({"a": "b"}, "a"),
-      "should return true": function(res) {
-        assert.isTrue(res);
+vows
+  .describe("exists")
+  .addBatch({
+    "A simple path": {
+      "as a string": {
+        topic: dotty.exists({ a: "b" }, "a"),
+        "should return true": function (res) {
+          assert.isTrue(res);
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.exists({"a": "b"}, ["a"]),
-      "should return true": function(res) {
-        assert.isTrue(res);
+      "as an array": {
+        topic: dotty.exists({ a: "b" }, ["a"]),
+        "should return true": function (res) {
+          assert.isTrue(res);
+        },
       },
     },
-  },
-  "A two-level path": {
-    "as a string": {
-      topic: dotty.exists({"a": {"b": "c"}}, "a.b"),
-      "should return true": function(res) {
-        assert.isTrue(res);
+    "A two-level path": {
+      "as a string": {
+        topic: dotty.exists({ a: { b: "c" } }, "a.b"),
+        "should return true": function (res) {
+          assert.isTrue(res);
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.exists({"a": {"b": "c"}}, ["a", "b"]),
-      "should return true": function(res) {
-        assert.isTrue(res);
+      "as an array": {
+        topic: dotty.exists({ a: { b: "c" } }, ["a", "b"]),
+        "should return true": function (res) {
+          assert.isTrue(res);
+        },
       },
     },
-  },
-  "An unresolved path": {
-    "as a string": {
-      topic: dotty.exists({"a": {"b": "c"}}, "a.x"),
-      "should return false": function(res) {
-        assert.isFalse(res);
+    "An unresolved path": {
+      "as a string": {
+        topic: dotty.exists({ a: { b: "c" } }, "a.x"),
+        "should return false": function (res) {
+          assert.isFalse(res);
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.exists({"a": {"b": "c"}}, ["a", "x"]),
-      "should return false": function(res) {
-        assert.isFalse(res);
+      "as an array": {
+        topic: dotty.exists({ a: { b: "c" } }, ["a", "x"]),
+        "should return false": function (res) {
+          assert.isFalse(res);
+        },
       },
     },
-  },
-  "A property which is literally undefined, but with a resolved path": {
-    "as a string": {
-      topic: dotty.exists({"a": {"b": undefined}}, "a.b"),
-      "should return true": function(res) {
-        assert.isTrue(res);
+    "A property which is literally undefined, but with a resolved path": {
+      "as a string": {
+        topic: dotty.exists({ a: { b: undefined } }, "a.b"),
+        "should return true": function (res) {
+          assert.isTrue(res);
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.exists({"a": {"b": undefined}}, ["a", "b"]),
-      "should return true": function(res) {
-        assert.isTrue(res);
+      "as an array": {
+        topic: dotty.exists({ a: { b: undefined } }, ["a", "b"]),
+        "should return true": function (res) {
+          assert.isTrue(res);
+        },
       },
     },
-  },
-}).export(module);
+  })
+  .export(module);

programming_language: JavaScript
filename: get-test.js
change_type: ModificationType.MODIFY
diff: @@ -1,62 +1,65 @@
 var dotty = require("../lib/index"),
-    vows = require("vows"),
-    assert = require("assert");
+  vows = require("vows"),
+  assert = require("assert");
 
-vows.describe("get").addBatch({
-  "A simple path": {
-    "as a string": {
-      topic: dotty.get({"a": "b"}, "a"),
-      "should return the correct value": function(res) {
-        assert.equal(res, "b");
+vows
+  .describe("get")
+  .addBatch({
+    "A simple path": {
+      "as a string": {
+        topic: dotty.get({ a: "b" }, "a"),
+        "should return the correct value": function (res) {
+          assert.equal(res, "b");
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.get({"a": "b"}, ["a"]),
-      "should return the correct value": function(res) {
-        assert.equal(res, "b");
+      "as an array": {
+        topic: dotty.get({ a: "b" }, ["a"]),
+        "should return the correct value": function (res) {
+          assert.equal(res, "b");
+        },
       },
     },
-  },
-  "A two-level path": {
-    "as a string": {
-      topic: dotty.get({"a": {"b": "c"}}, "a.b"),
-      "should return the correct value": function(res) {
-        assert.equal(res, "c");
+    "A two-level path": {
+      "as a string": {
+        topic: dotty.get({ a: { b: "c" } }, "a.b"),
+        "should return the correct value": function (res) {
+          assert.equal(res, "c");
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.get({"a": {"b": "c"}}, ["a", "b"]),
-      "should return the correct value": function(res) {
-        assert.equal(res, "c");
+      "as an array": {
+        topic: dotty.get({ a: { b: "c" } }, ["a", "b"]),
+        "should return the correct value": function (res) {
+          assert.equal(res, "c");
+        },
       },
     },
-  },
-  "An unresolved path": {
-    "as a string": {
-      topic: dotty.get({"a": {"b": "c"}}, "a.x"),
-      "should return undefined": function(res) {
-        assert.isUndefined(res);
+    "An unresolved path": {
+      "as a string": {
+        topic: dotty.get({ a: { b: "c" } }, "a.x"),
+        "should return undefined": function (res) {
+          assert.isUndefined(res);
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.get({"a": {"b": "c"}}, ["a", "x"]),
-      "should return undefined": function(res) {
-        assert.isUndefined(res);
+      "as an array": {
+        topic: dotty.get({ a: { b: "c" } }, ["a", "x"]),
+        "should return undefined": function (res) {
+          assert.isUndefined(res);
+        },
       },
     },
-  },
-  "A property which is literally undefined, but with a resolved path": {
-    "as a string": {
-      topic: dotty.get({"a": {"b": undefined}}, "a.b"),
-      "should return undefined": function(res) {
-        assert.isUndefined(res);
+    "A property which is literally undefined, but with a resolved path": {
+      "as a string": {
+        topic: dotty.get({ a: { b: undefined } }, "a.b"),
+        "should return undefined": function (res) {
+          assert.isUndefined(res);
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.get({"a": {"b": undefined}}, ["a", "b"]),
-      "should return undefined": function(res) {
-        assert.isUndefined(res);
+      "as an array": {
+        topic: dotty.get({ a: { b: undefined } }, ["a", "b"]),
+        "should return undefined": function (res) {
+          assert.isUndefined(res);
+        },
       },
     },
-  },
-}).export(module);
+  })
+  .export(module);

programming_language: JavaScript
filename: put-test.js
change_type: ModificationType.MODIFY
diff: @@ -1,48 +1,73 @@
 var dotty = require("../lib/index"),
-    vows = require("vows"),
-    assert = require("assert");
+  vows = require("vows"),
+  assert = require("assert");
 
-vows.describe("put").addBatch({
-  "A simple path": {
-    "as a string": {
-      topic: (function() { var x = {}; dotty.put(x, "a", "b"); return x; }()),
-      "should set the correct value": function(res) {
-        assert.equal(res.a, "b");
+vows
+  .describe("put")
+  .addBatch({
+    "A simple path": {
+      "as a string": {
+        topic: (function () {
+          var x = {};
+          dotty.put(x, "a", "b");
+          return x;
+        })(),
+        "should set the correct value": function (res) {
+          assert.equal(res.a, "b");
+        },
       },
-    },
-    "as an array": {
-      topic: (function() { var x = {}; dotty.put(x, ["a"], "b"); return x; }()),
-      "should set the correct value": function(res) {
-        assert.equal(res.a, "b");
+      "as an array": {
+        topic: (function () {
+          var x = {};
+          dotty.put(x, ["a"], "b");
+          return x;
+        })(),
+        "should set the correct value": function (res) {
+          assert.equal(res.a, "b");
+        },
       },
     },
-  },
-  "A two-level path": {
-    "as a string": {
-      topic: (function() { var x = {}; dotty.put(x, "a.b", "c"); return x; }()),
-      "should set the correct value": function(res) {
-        assert.equal(res.a.b, "c");
+    "A two-level path": {
+      "as a string": {
+        topic: (function () {
+          var x = {};
+          dotty.put(x, "a.b", "c");
+          return x;
+        })(),
+        "should set the correct value": function (res) {
+          assert.equal(res.a.b, "c");
+        },
       },
-    },
-    "as an array": {
-      topic: (function() { var x = {}; dotty.put(x, ["a", "b"], "c"); return x; }()),
-      "should set the correct value": function(res) {
-        assert.equal(res.a.b, "c");
+      "as an array": {
+        topic: (function () {
+          var x = {};
+          dotty.put(x, ["a", "b"], "c");
+          return x;
+        })(),
+        "should set the correct value": function (res) {
+          assert.equal(res.a.b, "c");
+        },
       },
     },
-  },
-  "An interrupted path": {
-    "as a string": {
-      topic: (function() { var x = {a: 1}; return dotty.put(x, "a.b", "c"); }()),
-      "should return false": function(res) {
-        assert.isFalse(res);
+    "An interrupted path": {
+      "as a string": {
+        topic: (function () {
+          var x = { a: 1 };
+          return dotty.put(x, "a.b", "c");
+        })(),
+        "should return false": function (res) {
+          assert.isFalse(res);
+        },
       },
-    },
-    "as an array": {
-      topic: (function() { var x = {a: 1}; return dotty.put(x, ["a", "b"], "c"); }()),
-      "should return false": function(res) {
-        assert.isFalse(res);
+      "as an array": {
+        topic: (function () {
+          var x = { a: 1 };
+          return dotty.put(x, ["a", "b"], "c");
+        })(),
+        "should return false": function (res) {
+          assert.isFalse(res);
+        },
       },
     },
-  },
-}).export(module);
+  })
+  .export(module);

programming_language: JavaScript
filename: remove-test.js
change_type: ModificationType.MODIFY
diff: @@ -1,48 +1,73 @@
 var dotty = require("../lib/index"),
-    vows = require("vows"),
-    assert = require("assert");
+  vows = require("vows"),
+  assert = require("assert");
 
-vows.describe("remove").addBatch({
-  "A simple path": {
-    "as a string": {
-      topic: (function() { var x = {a: 1}; dotty.remove(x, "a"); return x; }()),
-      "should remove the property": function(res) {
-        assert.isUndefined(res.a);
+vows
+  .describe("remove")
+  .addBatch({
+    "A simple path": {
+      "as a string": {
+        topic: (function () {
+          var x = { a: 1 };
+          dotty.remove(x, "a");
+          return x;
+        })(),
+        "should remove the property": function (res) {
+          assert.isUndefined(res.a);
+        },
       },
-    },
-    "as an array": {
-      topic: (function() { var x = {a: 1}; dotty.remove(x, ["a"]); return x; }()),
-      "should remove the property": function(res) {
-        assert.isUndefined(res.a);
+      "as an array": {
+        topic: (function () {
+          var x = { a: 1 };
+          dotty.remove(x, ["a"]);
+          return x;
+        })(),
+        "should remove the property": function (res) {
+          assert.isUndefined(res.a);
+        },
       },
     },
-  },
-  "A two-level path": {
-    "as a string": {
-      topic: (function() { var x = {a: {b: 1}}; dotty.remove(x, "a.b"); return x; }()),
-      "should remove the property": function(res) {
-        assert.isUndefined(res.a.b);
+    "A two-level path": {
+      "as a string": {
+        topic: (function () {
+          var x = { a: { b: 1 } };
+          dotty.remove(x, "a.b");
+          return x;
+        })(),
+        "should remove the property": function (res) {
+          assert.isUndefined(res.a.b);
+        },
       },
-    },
-    "as an array": {
-      topic: (function() { var x = {a: {b: 1}}; dotty.remove(x, ["a", "b"]); return x; }()),
-      "should remove the property": function(res) {
-        assert.isUndefined(res.a.b);
+      "as an array": {
+        topic: (function () {
+          var x = { a: { b: 1 } };
+          dotty.remove(x, ["a", "b"]);
+          return x;
+        })(),
+        "should remove the property": function (res) {
+          assert.isUndefined(res.a.b);
+        },
       },
     },
-  },
-  "An interrupted path": {
-    "as a string": {
-      topic: (function() { var x = {a: 1}; return dotty.remove(x, "a.b"); }()),
-      "should return false": function(res) {
-        assert.isFalse(res);
+    "An interrupted path": {
+      "as a string": {
+        topic: (function () {
+          var x = { a: 1 };
+          return dotty.remove(x, "a.b");
+        })(),
+        "should return false": function (res) {
+          assert.isFalse(res);
+        },
       },
-    },
-    "as an array": {
-      topic: (function() { var x = {a: 1}; return dotty.remove(x, ["a", "b"]); }()),
-      "should return false": function(res) {
-        assert.isFalse(res);
+      "as an array": {
+        topic: (function () {
+          var x = { a: 1 };
+          return dotty.remove(x, ["a", "b"]);
+        })(),
+        "should return false": function (res) {
+          assert.isFalse(res);
+        },
       },
     },
-  },
-}).export(module);
+  })
+  .export(module);

programming_language: JavaScript
filename: removesearch-test.js
change_type: ModificationType.MODIFY
diff: @@ -1,145 +1,171 @@
 var dotty = require("../lib/index"),
-    vows = require("vows"),
-    assert = require("assert");
+  vows = require("vows"),
+  assert = require("assert");
 
-vows.describe("search").addBatch({
-  "A simple path": {
-    "as a string": {
-      topic: dotty.removeSearch({"a": "b"}, "a"),
-      "should return an object with no keys": function(res) {
-        assert.isObject(res);
-        assert.equal(Object.keys(res).length, 0, "Object should have no keys");
+vows
+  .describe("search")
+  .addBatch({
+    "A simple path": {
+      "as a string": {
+        topic: dotty.removeSearch({ a: "b" }, "a"),
+        "should return an object with no keys": function (res) {
+          assert.isObject(res);
+          assert.equal(
+            Object.keys(res).length,
+            0,
+            "Object should have no keys"
+          );
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.removeSearch({"a": "b"}, ["a"]),
-      "should return an object with no keys": function(res) {
-        assert.isObject(res);
-        assert.equal(Object.keys(res).length, 0, "Object should have no keys");
+      "as an array": {
+        topic: dotty.removeSearch({ a: "b" }, ["a"]),
+        "should return an object with no keys": function (res) {
+          assert.isObject(res);
+          assert.equal(
+            Object.keys(res).length,
+            0,
+            "Object should have no keys"
+          );
+        },
       },
-    },
-    "as an array with a regex": {
-      topic: dotty.removeSearch({"a": "b"}, [/a/]),
-      "should return an object with no keys": function(res) {
-        assert.isObject(res);
-        assert.equal(Object.keys(res).length, 0, "Object should have no keys");
+      "as an array with a regex": {
+        topic: dotty.removeSearch({ a: "b" }, [/a/]),
+        "should return an object with no keys": function (res) {
+          assert.isObject(res);
+          assert.equal(
+            Object.keys(res).length,
+            0,
+            "Object should have no keys"
+          );
+        },
       },
     },
-  },
-  "A two-level path": {
-    "as a string": {
-      topic: dotty.removeSearch({"a": {"b": "c"}}, "a.b"),
-      "should return an object with b removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.equal(Object.keys(res.a), 0, "a has no keys");
+    "A two-level path": {
+      "as a string": {
+        topic: dotty.removeSearch({ a: { b: "c" } }, "a.b"),
+        "should return an object with b removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.equal(Object.keys(res.a), 0, "a has no keys");
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.removeSearch({"a": {"b": "c"}}, ["a", "b"]),
-      "should return an object with b removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.equal(Object.keys(res.a), 0, "a has no keys");
+      "as an array": {
+        topic: dotty.removeSearch({ a: { b: "c" } }, ["a", "b"]),
+        "should return an object with b removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.equal(Object.keys(res.a), 0, "a has no keys");
+        },
       },
-    },
-    "as an array with regexes": {
-      topic: dotty.removeSearch({"a": {"b": "c"}}, [/a/, /b/]),
-      "should return an object with b removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.equal(Object.keys(res.a), 0, "a has no keys");
+      "as an array with regexes": {
+        topic: dotty.removeSearch({ a: { b: "c" } }, [/a/, /b/]),
+        "should return an object with b removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.equal(Object.keys(res.a), 0, "a has no keys");
+        },
       },
     },
-  },
-  "A two-level path matching two values": {
-    "as a string": {
-      topic: dotty.removeSearch({"a": {"b": "c", "d": "e"}}, "a.*"),
-      "should return an object with b & d removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.equal(Object.keys(res.a), 0, "a has no keys");
+    "A two-level path matching two values": {
+      "as a string": {
+        topic: dotty.removeSearch({ a: { b: "c", d: "e" } }, "a.*"),
+        "should return an object with b & d removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.equal(Object.keys(res.a), 0, "a has no keys");
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.removeSearch({"a": {"b": "c", "d": "e"}}, ["a", "*"]),
-      "should return an object with b & d removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.equal(Object.keys(res.a), 0, "a has no keys");
+      "as an array": {
+        topic: dotty.removeSearch({ a: { b: "c", d: "e" } }, ["a", "*"]),
+        "should return an object with b & d removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.equal(Object.keys(res.a), 0, "a has no keys");
+        },
       },
-    },
-    "as an array with regexes": {
-      topic: dotty.removeSearch({"a": {"b": "c", "d": "e"}}, [/a/, /.*/]),
-      "should return an object with b & d removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.equal(Object.keys(res.a), 0, "a has no keys");
+      "as an array with regexes": {
+        topic: dotty.removeSearch({ a: { b: "c", d: "e" } }, [/a/, /.*/]),
+        "should return an object with b & d removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.equal(Object.keys(res.a), 0, "a has no keys");
+        },
       },
     },
-  },
-  "A three-level mixed path matching two values": {
-    "as a string": {
-      topic: dotty.removeSearch({"a": {"b": {"x": "y"}, "c": {"x": "z"}}}, "a.*.x"),
-      "should return an object with x removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.isObject(res.a.b);
-        assert.isObject(res.a.c);
-        assert.equal(Object.keys(res.a.b), 0, "b has no keys");
-        assert.equal(Object.keys(res.a.c), 0, "c has no keys");
+    "A three-level mixed path matching two values": {
+      "as a string": {
+        topic: dotty.removeSearch(
+          { a: { b: { x: "y" }, c: { x: "z" } } },
+          "a.*.x"
+        ),
+        "should return an object with x removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.isObject(res.a.b);
+          assert.isObject(res.a.c);
+          assert.equal(Object.keys(res.a.b), 0, "b has no keys");
+          assert.equal(Object.keys(res.a.c), 0, "c has no keys");
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.removeSearch({"a": {"b": {"x": "y"}, "c": {"x": "z"}}}, ["a", "*", "x"]),
-      "should return an object with x removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.isObject(res.a.b);
-        assert.isObject(res.a.c);
-        assert.equal(Object.keys(res.a.b), 0, "b has no keys");
-        assert.equal(Object.keys(res.a.c), 0, "c has no keys");
+      "as an array": {
+        topic: dotty.removeSearch({ a: { b: { x: "y" }, c: { x: "z" } } }, [
+          "a",
+          "*",
+          "x",
+        ]),
+        "should return an object with x removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.isObject(res.a.b);
+          assert.isObject(res.a.c);
+          assert.equal(Object.keys(res.a.b), 0, "b has no keys");
+          assert.equal(Object.keys(res.a.c), 0, "c has no keys");
+        },
       },
-    },
-    "as an array with regexes": {
-      topic: dotty.removeSearch({"a": {"b": {"x": "y"}, "c": {"x": "z"}}}, [/a/, /.*/, /x/]),
-      "should return an object with x removed": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.isObject(res.a.b);
-        assert.isObject(res.a.c);
-        assert.equal(Object.keys(res.a.b), 0, "b has no keys");
-        assert.equal(Object.keys(res.a.c), 0, "c has no keys");
+      "as an array with regexes": {
+        topic: dotty.removeSearch({ a: { b: { x: "y" }, c: { x: "z" } } }, [
+          /a/,
+          /.*/,
+          /x/,
+        ]),
+        "should return an object with x removed": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.isObject(res.a.b);
+          assert.isObject(res.a.c);
+          assert.equal(Object.keys(res.a.b), 0, "b has no keys");
+          assert.equal(Object.keys(res.a.c), 0, "c has no keys");
+        },
       },
     },
-  },
-  "An unresolved path": {
-    "as a string": {
-      topic: dotty.removeSearch({"a": {"b": "c"}}, "a.x"),
-      "should return unmodified object": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.isString(res.a.b);
-        assert.equal(res.a.b, 'c');
+    "An unresolved path": {
+      "as a string": {
+        topic: dotty.removeSearch({ a: { b: "c" } }, "a.x"),
+        "should return unmodified object": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.isString(res.a.b);
+          assert.equal(res.a.b, "c");
+        },
       },
-    },
-    "as an array": {
-      topic: dotty.removeSearch({"a": {"b": "c"}}, ["a", "x"]),
-      "should return unmodified object": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.isString(res.a.b);
-        assert.equal(res.a.b, 'c');
+      "as an array": {
+        topic: dotty.removeSearch({ a: { b: "c" } }, ["a", "x"]),
+        "should return unmodified object": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.isString(res.a.b);
+          assert.equal(res.a.b, "c");
+        },
       },
-    },
-    "as an array with regexes": {
-      topic: dotty.removeSearch({"a": {"b": "c"}}, [/a/, /x/]),
-      "should return unmodified object": function(res) {
-        assert.isObject(res);
-        assert.isObject(res.a);
-        assert.isString(res.a.b);
-        assert.equal(res.a.b, 'c');
+      "as an array with regexes": {
+        topic: dotty.removeSearch({ a: { b: "c" } }, [/a/, /x/]),
+        "should return unmodified object": function (res) {
+          assert.isObject(res);
+          assert.isObject(res.a);
+          assert.isString(res.a.b);
+          assert.equal(res.a.b, "c");
+        },
       },
     },
-  },
-}).export(module);
+  })
+  .export(module);

programming_language: JavaScript
filename: search-test.js
change_type: ModificationType.MODIFY
diff: @@ -1,193 +1,204 @@
 var dotty = require("../lib/index"),
-    vows = require("vows"),
-    assert = require("assert");
+  vows = require("vows"),
+  assert = require("assert");
 
-vows.describe("search").addBatch({
-  "A simple path": {
-    "as a string": {
-      topic: dotty.search({"a": "b"}, "a"),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return one value": function(res) {
-        assert.equal(res.length, 1);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "b");
-      },
-    },
-    "as an array": {
-      topic: dotty.search({"a": "b"}, ["a"]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return one value": function(res) {
-        assert.equal(res.length, 1);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "b");
-      },
-    },
-    "as an array with a regex": {
-      topic: dotty.search({"a": "b"}, [/a/]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return one value": function(res) {
-        assert.equal(res.length, 1);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "b");
-      },
-    },
-  },
-  "A two-level path": {
-    "as a string": {
-      topic: dotty.search({"a": {"b": "c"}}, "a.b"),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return one value": function(res) {
-        assert.equal(res.length, 1);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "c");
-      },
-    },
-    "as an array": {
-      topic: dotty.search({"a": {"b": "c"}}, ["a", "b"]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return one value": function(res) {
-        assert.equal(res.length, 1);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "c");
+vows
+  .describe("search")
+  .addBatch({
+    "A simple path": {
+      "as a string": {
+        topic: dotty.search({ a: "b" }, "a"),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return one value": function (res) {
+          assert.equal(res.length, 1);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "b");
+        },
+      },
+      "as an array": {
+        topic: dotty.search({ a: "b" }, ["a"]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return one value": function (res) {
+          assert.equal(res.length, 1);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "b");
+        },
+      },
+      "as an array with a regex": {
+        topic: dotty.search({ a: "b" }, [/a/]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return one value": function (res) {
+          assert.equal(res.length, 1);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "b");
+        },
       },
     },
-    "as an array with regexes": {
-      topic: dotty.search({"a": {"b": "c"}}, [/a/, /b/]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return one value": function(res) {
-        assert.equal(res.length, 1);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "c");
+    "A two-level path": {
+      "as a string": {
+        topic: dotty.search({ a: { b: "c" } }, "a.b"),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return one value": function (res) {
+          assert.equal(res.length, 1);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "c");
+        },
+      },
+      "as an array": {
+        topic: dotty.search({ a: { b: "c" } }, ["a", "b"]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return one value": function (res) {
+          assert.equal(res.length, 1);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "c");
+        },
+      },
+      "as an array with regexes": {
+        topic: dotty.search({ a: { b: "c" } }, [/a/, /b/]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return one value": function (res) {
+          assert.equal(res.length, 1);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "c");
+        },
       },
     },
-  },
-  "A two-level path matching two values": {
-    "as a string": {
-      topic: dotty.search({"a": {"b": "c", "d": "e"}}, "a.*"),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return two values": function(res) {
-        assert.equal(res.length, 2);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "c");
-        assert.equal(res[1], "e");
+    "A two-level path matching two values": {
+      "as a string": {
+        topic: dotty.search({ a: { b: "c", d: "e" } }, "a.*"),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return two values": function (res) {
+          assert.equal(res.length, 2);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "c");
+          assert.equal(res[1], "e");
+        },
+      },
+      "as an array": {
+        topic: dotty.search({ a: { b: "c", d: "e" } }, ["a", "*"]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return two values": function (res) {
+          assert.equal(res.length, 2);
+        },
+        "should return the correct values": function (res) {
+          assert.equal(res[0], "c");
+          assert.equal(res[1], "e");
+        },
+      },
+      "as an array with regexes": {
+        topic: dotty.search({ a: { b: "c", d: "e" } }, [/a/, /.*/]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return two values": function (res) {
+          assert.equal(res.length, 2);
+        },
+        "should return the correct values": function (res) {
+          assert.equal(res[0], "c");
+          assert.equal(res[1], "e");
+        },
       },
     },
-    "as an array": {
-      topic: dotty.search({"a": {"b": "c", "d": "e"}}, ["a", "*"]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return two values": function(res) {
-        assert.equal(res.length, 2);
-      },
-      "should return the correct values": function(res) {
-        assert.equal(res[0], "c");
-        assert.equal(res[1], "e");
+    "A three-level mixed path matching two values": {
+      "as a string": {
+        topic: dotty.search({ a: { b: { x: "y" }, c: { x: "z" } } }, "a.*.x"),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return two values": function (res) {
+          assert.equal(res.length, 2);
+        },
+        "should return the correct value": function (res) {
+          assert.equal(res[0], "y");
+          assert.equal(res[1], "z");
+        },
+      },
+      "as an array": {
+        topic: dotty.search({ a: { b: { x: "y" }, c: { x: "z" } } }, [
+          "a",
+          "*",
+          "x",
+        ]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return two values": function (res) {
+          assert.equal(res.length, 2);
+        },
+        "should return the correct values": function (res) {
+          assert.equal(res[0], "y");
+          assert.equal(res[1], "z");
+        },
+      },
+      "as an array with regexes": {
+        topic: dotty.search({ a: { b: { x: "y" }, c: { x: "z" } } }, [
+          /a/,
+          /.*/,
+          /x/,
+        ]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return two values": function (res) {
+          assert.equal(res.length, 2);
+        },
+        "should return the correct values": function (res) {
+          assert.equal(res[0], "y");
+          assert.equal(res[1], "z");
+        },
       },
     },
-    "as an array with regexes": {
-      topic: dotty.search({"a": {"b": "c", "d": "e"}}, [/a/, /.*/]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return two values": function(res) {
-        assert.equal(res.length, 2);
-      },
-      "should return the correct values": function(res) {
-        assert.equal(res[0], "c");
-        assert.equal(res[1], "e");
-      },
-    },
-  },
-  "A three-level mixed path matching two values": {
-    "as a string": {
-      topic: dotty.search({"a": {"b": {"x": "y"}, "c": {"x": "z"}}}, "a.*.x"),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return two values": function(res) {
-        assert.equal(res.length, 2);
-      },
-      "should return the correct value": function(res) {
-        assert.equal(res[0], "y");
-        assert.equal(res[1], "z");
-      },
-    },
-    "as an array": {
-      topic: dotty.search({"a": {"b": {"x": "y"}, "c": {"x": "z"}}}, ["a", "*", "x"]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return two values": function(res) {
-        assert.equal(res.length, 2);
-      },
-      "should return the correct values": function(res) {
-        assert.equal(res[0], "y");
-        assert.equal(res[1], "z");
-      },
-    },
-    "as an array with regexes": {
-      topic: dotty.search({"a": {"b": {"x": "y"}, "c": {"x": "z"}}}, [/a/, /.*/, /x/]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return two values": function(res) {
-        assert.equal(res.length, 2);
-      },
-      "should return the correct values": function(res) {
-        assert.equal(res[0], "y");
-        assert.equal(res[1], "z");
-      },
-    },
-  },
-  "An unresolved path": {
-    "as a string": {
-      topic: dotty.search({"a": {"b": "c"}}, "a.x"),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return zero values": function(res) {
-        assert.equal(res.length, 0);
-      },
-    },
-    "as an array": {
-      topic: dotty.search({"a": {"b": "c"}}, ["a", "x"]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return zero values": function(res) {
-        assert.equal(res.length, 0);
-      },
-    },
-    "as an array with regexes": {
-      topic: dotty.search({"a": {"b": "c"}}, [/a/, /x/]),
-      "should return an array": function(res) {
-        assert.isArray(res);
-      },
-      "should return zero values": function(res) {
-        assert.equal(res.length, 0);
+    "An unresolved path": {
+      "as a string": {
+        topic: dotty.search({ a: { b: "c" } }, "a.x"),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return zero values": function (res) {
+          assert.equal(res.length, 0);
+        },
+      },
+      "as an array": {
+        topic: dotty.search({ a: { b: "c" } }, ["a", "x"]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return zero values": function (res) {
+          assert.equal(res.length, 0);
+        },
+      },
+      "as an array with regexes": {
+        topic: dotty.search({ a: { b: "c" } }, [/a/, /x/]),
+        "should return an array": function (res) {
+          assert.isArray(res);
+        },
+        "should return zero values": function (res) {
+          assert.equal(res.length, 0);
+        },
       },
     },
-  },
-}).export(module);
+  })
+  .export(module);

programming_language: JavaScript
filename: security-test.js
change_type: ModificationType.ADD
diff: @@ -0,0 +1,29 @@
+var dotty = require("../lib/index"),
+  vows = require("vows"),
+  assert = require("assert");
+
+vows
+  .describe("security")
+  .addBatch({
+    "When we attempt to update the prototype": {
+      topic() {
+        var obj = {};
+        dotty.put(obj, "__proto__.polluted", "Muhahahaha");
+        return obj;
+      },
+      "it should not update": function (res) {
+        assert.equal(res.polluted, undefined);
+      },
+    },
+    "When we attempt to update the constructor prototype": {
+      topic() {
+        var obj = {};
+        dotty.put(obj, "constructor.prototype.polluted", "Muhahahaha");
+        return obj;
+      },
+      "it should not update": function (res) {
+        assert.equal(res.polluted, undefined);
+      },
+    },
+  })
+  .export(module);

programming_language: JavaScript