Prototype Pollution
Description
A type confusion flaw in dotty before 0.1.2 allows prototype pollution via array keys, bypassing a previous fix.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A type confusion flaw in dotty before 0.1.2 allows prototype pollution via array keys, bypassing a previous fix.
Vulnerability
The package dotty before version 0.1.2 contains a type confusion vulnerability that can lead to prototype pollution. The issue specifically arises when user-provided keys used in the path parameter are arrays. Prior to the fix, the put function did not coerce array elements to strings, allowing the insertion of special keys like __proto__ and bypassing the protection added for CVE-2021-25912. The vulnerable versions are all releases before 0.1.2. [1][2]
Exploitation
An attacker can exploit this vulnerability by providing a path argument that is an array containing a key like __proto__ (or constructor, prototype) as an element. When dotty.put is called with such an array, the type confusion prevents the existing __proto__ check from triggering, enabling the attacker to overwrite Object.prototype properties. No special network position or authentication is required beyond the ability to pass crafted input to a function that uses dotty. [2][3]
Impact
Successful exploitation results in prototype pollution, where properties are injected into the base Object.prototype. This can lead to denial of service via exceptions, or in certain application contexts, remote code execution if the polluted properties influence security decisions or code paths. The attacker can effectively tamper with all objects in the JavaScript runtime. [3]
Mitigation
Version 0.1.2 fixes the issue by converting array path elements to strings with "" + path.shift(), ensuring that special keys like __proto__ are correctly detected and blocked. Users should upgrade to dotty 0.1.2 or later. No workaround is provided for older versions. The fix commit is at GitHub [2]. The vulnerability is not listed in CISA's Known Exploited Vulnerabilities catalog as of this writing. [2]
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
dottynpm | < 0.1.2 | 0.1.2 |
Affected products
2- dotty/dottydescription
Patches
188f61860dcc2Address different method of prototype pollution (#32)
12 files changed · +241 −191
docs/docco.css+6 −6 modified@@ -213,7 +213,7 @@ ul.sections > li > div { /*---------------------- Low resolutions (> 320px) ---------------------*/ @media only screen and (min-width: 320px) { - .pilwrap { display: none; } + .sswrap { display: none; } ul.sections > li > div { display: block; @@ -330,12 +330,12 @@ ul.sections > li > div { box-shadow: none; } - .pilwrap { + .sswrap { position: relative; display: inline; } - .pilcrow { + .ss { font: 12px Arial; text-decoration: none; color: #454545; @@ -345,14 +345,14 @@ ul.sections > li > div { opacity: 0; -webkit-transition: opacity 0.2s linear; } - .for-h1 .pilcrow { + .for-h1 .ss { top: 47px; } - .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow { + .for-h2 .ss, .for-h3 .ss, .for-h4 .ss { top: 35px; } - ul.sections > li > div.annotation:hover .pilcrow { + ul.sections > li > div.annotation:hover .ss { opacity: 1; } }
docs/lib/index.html+97 −97 modified@@ -24,8 +24,8 @@ <h1>index.js</h1> <li id="section-1"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-1">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-1">§</a> </div> <p>Dotty makes it easy to programmatically access arbitrarily nested objects and their properties.</p> @@ -38,8 +38,8 @@ <h1>index.js</h1> <li id="section-2"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-2">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-2">§</a> </div> <p><code>object</code> is an object, <code>path</code> is the path to the property you want to check for existence of.</p> @@ -50,27 +50,27 @@ <h1>index.js</h1> </div> <div class="content"><div class='highlight'><pre> -<span class="hljs-keyword">var</span> exists = (<span class="hljs-built_in">module</span>.exports.exists = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exists</span>(<span class="hljs-params">object, path</span>) </span>{ - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { - path = path.split(<span class="hljs-string">"."</span>); +<span class="hljs-keyword">var</span> exists = (<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">exists</span> = <span class="hljs-keyword">function</span> <span class="hljs-title function_">exists</span>(<span class="hljs-params">object, path</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { + path = path.<span class="hljs-title function_">split</span>(<span class="hljs-string">"."</span>); } - <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) || path.length === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>) || path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } - path = path.slice(); + path = path.<span class="hljs-title function_">slice</span>(); - <span class="hljs-keyword">var</span> key = path.shift(); + <span class="hljs-keyword">var</span> key = path.<span class="hljs-title function_">shift</span>(); - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } - <span class="hljs-keyword">if</span> (path.length === <span class="hljs-number">0</span>) { - <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.hasOwnProperty.apply(object, [key]); + <span class="hljs-keyword">if</span> (path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">return</span> <span class="hljs-title class_">Object</span>.<span class="hljs-property">hasOwnProperty</span>.<span class="hljs-title function_">apply</span>(object, [key]); } <span class="hljs-keyword">else</span> { - <span class="hljs-keyword">return</span> exists(object[key], path); + <span class="hljs-keyword">return</span> <span class="hljs-title function_">exists</span>(object[key], path); } });</pre></div></div> @@ -80,8 +80,8 @@ <h1>index.js</h1> <li id="section-3"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-3">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-3">§</a> </div> <p>These arguments are the same as those for <code>exists</code>.</p> <p>The return value, however, is the property you’re trying to access, or @@ -93,29 +93,29 @@ <h1>index.js</h1> </div> <div class="content"><div class='highlight'><pre> -<span class="hljs-keyword">var</span> get = (<span class="hljs-built_in">module</span>.exports.get = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get</span>(<span class="hljs-params">object, path</span>) </span>{ - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { - path = path.split(<span class="hljs-string">"."</span>); +<span class="hljs-keyword">var</span> get = (<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">get</span> = <span class="hljs-keyword">function</span> <span class="hljs-title function_">get</span>(<span class="hljs-params">object, path</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { + path = path.<span class="hljs-title function_">split</span>(<span class="hljs-string">"."</span>); } - <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) || path.length === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>) || path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { <span class="hljs-keyword">return</span>; } - path = path.slice(); + path = path.<span class="hljs-title function_">slice</span>(); - <span class="hljs-keyword">var</span> key = path.shift(); + <span class="hljs-keyword">var</span> key = path.<span class="hljs-title function_">shift</span>(); - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span>; } - <span class="hljs-keyword">if</span> (path.length === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { <span class="hljs-keyword">return</span> object[key]; } - <span class="hljs-keyword">if</span> (path.length) { - <span class="hljs-keyword">return</span> get(object[key], path); + <span class="hljs-keyword">if</span> (path.<span class="hljs-property">length</span>) { + <span class="hljs-keyword">return</span> <span class="hljs-title function_">get</span>(object[key], path); } });</pre></div></div> @@ -125,8 +125,8 @@ <h1>index.js</h1> <li id="section-4"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-4">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-4">§</a> </div> <p>Arguments are similar to <code>exists</code> and <code>get</code>, with the exception that path components are regexes with some special cases. If a path component is <code>"*"</code> @@ -139,48 +139,48 @@ <h1>index.js</h1> </div> <div class="content"><div class='highlight'><pre> -<span class="hljs-keyword">var</span> search = (<span class="hljs-built_in">module</span>.exports.search = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">object, path, action</span>) </span>{ - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { - path = path.split(<span class="hljs-string">"."</span>); +<span class="hljs-keyword">var</span> search = (<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">search</span> = <span class="hljs-keyword">function</span> <span class="hljs-title function_">search</span>(<span class="hljs-params">object, path, action</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { + path = path.<span class="hljs-title function_">split</span>(<span class="hljs-string">"."</span>); } - <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) || path.length === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>) || path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { <span class="hljs-keyword">return</span>; } - path = path.slice(); + path = path.<span class="hljs-title function_">slice</span>(); - <span class="hljs-keyword">var</span> key = path.shift(); + <span class="hljs-keyword">var</span> key = path.<span class="hljs-title function_">shift</span>(); - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span>; } - <span class="hljs-keyword">if</span> (key === <span class="hljs-string">"*"</span>) { - key = <span class="hljs-string">".*"</span>; + <span class="hljs-keyword">if</span> (key === <span class="hljs-string">"*"</span>) { + key = <span class="hljs-string">".*"</span>; } - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> key === <span class="hljs-string">"string"</span>) { - key = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(key); + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> key === <span class="hljs-string">"string"</span>) { + key = <span class="hljs-keyword">new</span> <span class="hljs-title class_">RegExp</span>(key); } - <span class="hljs-keyword">if</span> (path.length === <span class="hljs-number">0</span>) { - <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.keys(object) - .filter(key.test.bind(key)) - .map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">k</span>) </span>{ + <span class="hljs-keyword">if</span> (path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">return</span> <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">keys</span>(object) + .<span class="hljs-title function_">filter</span>(key.<span class="hljs-property">test</span>.<span class="hljs-title function_">bind</span>(key)) + .<span class="hljs-title function_">map</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">k</span>) { <span class="hljs-keyword">var</span> value = object[k]; <span class="hljs-keyword">if</span> (action) { - action(value, object, k); + <span class="hljs-title function_">action</span>(value, object, k); } <span class="hljs-keyword">return</span> value; }); } <span class="hljs-keyword">else</span> { - <span class="hljs-keyword">return</span> <span class="hljs-built_in">Array</span>.prototype.concat.apply( + <span class="hljs-keyword">return</span> <span class="hljs-title class_">Array</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>.<span class="hljs-property">concat</span>.<span class="hljs-title function_">apply</span>( [], - <span class="hljs-built_in">Object</span>.keys(object) - .filter(key.test.bind(key)) - .map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">k</span>) </span>{ - <span class="hljs-keyword">return</span> search(object[k], path, action); + <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">keys</span>(object) + .<span class="hljs-title function_">filter</span>(key.<span class="hljs-property">test</span>.<span class="hljs-title function_">bind</span>(key)) + .<span class="hljs-title function_">map</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">k</span>) { + <span class="hljs-keyword">return</span> <span class="hljs-title function_">search</span>(object[k], path, action); }) ); } @@ -192,20 +192,20 @@ <h1>index.js</h1> <li id="section-5"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-5">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-5">§</a> </div> <p>Perform a search and remove the matched keys. The return value is the same object argument with modifications.</p> </div> <div class="content"><div class='highlight'><pre> -<span class="hljs-keyword">var</span> removeSearch = (<span class="hljs-built_in">module</span>.exports.removeSearch = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removeSearch</span>(<span class="hljs-params"> +<span class="hljs-keyword">var</span> removeSearch = (<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">removeSearch</span> = <span class="hljs-keyword">function</span> <span class="hljs-title function_">removeSearch</span>(<span class="hljs-params"> object, path -</span>) </span>{ - search(object, path, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">value, object, key</span>) </span>{ +</span>) { + <span class="hljs-title function_">search</span>(object, path, <span class="hljs-keyword">function</span> (<span class="hljs-params">value, object, key</span>) { <span class="hljs-keyword">delete</span> object[key]; }); <span class="hljs-keyword">return</span> object; @@ -217,8 +217,8 @@ <h1>index.js</h1> <li id="section-6"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-6">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-6">§</a> </div> <p>The first two arguments for <code>put</code> are the same as <code>exists</code> and <code>get</code>.</p> <p>The third argument is a value to <code>put</code> at the <code>path</code> of the <code>object</code>. @@ -231,34 +231,34 @@ <h1>index.js</h1> </div> <div class="content"><div class='highlight'><pre> -<span class="hljs-keyword">var</span> put = (<span class="hljs-built_in">module</span>.exports.put = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">put</span>(<span class="hljs-params">object, path, value</span>) </span>{ - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { - path = path.split(<span class="hljs-string">"."</span>); +<span class="hljs-keyword">var</span> put = (<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">put</span> = <span class="hljs-keyword">function</span> <span class="hljs-title function_">put</span>(<span class="hljs-params">object, path, value</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { + path = path.<span class="hljs-title function_">split</span>(<span class="hljs-string">"."</span>); } - <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) || path.length === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>) || path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } - path = path.slice(); + path = path.<span class="hljs-title function_">slice</span>(); - <span class="hljs-keyword">var</span> key = path.shift(); + <span class="hljs-keyword">var</span> key = <span class="hljs-string">""</span> + path.<span class="hljs-title function_">shift</span>(); - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span> || key === <span class="hljs-string">"__proto__"</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span> || key === <span class="hljs-string">"__proto__"</span>) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } - <span class="hljs-keyword">if</span> (path.length === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { object[key] = value; } <span class="hljs-keyword">else</span> { - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object[key] === <span class="hljs-string">"undefined"</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object[key] === <span class="hljs-string">"undefined"</span>) { object[key] = {}; } - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object[key] !== <span class="hljs-string">"object"</span> || object[key] === <span class="hljs-literal">null</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object[key] !== <span class="hljs-string">"object"</span> || object[key] === <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } - <span class="hljs-keyword">return</span> put(object[key], path, value); + <span class="hljs-keyword">return</span> <span class="hljs-title function_">put</span>(object[key], path, value); } });</pre></div></div> @@ -268,8 +268,8 @@ <h1>index.js</h1> <li id="section-7"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-7">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-7">§</a> </div> <p><code>remove</code> is like <code>put</code> in reverse!</p> <p>The return value is <code>true</code> in the case that the value existed and was removed @@ -278,33 +278,33 @@ <h1>index.js</h1> </div> <div class="content"><div class='highlight'><pre> -<span class="hljs-keyword">var</span> remove = (<span class="hljs-built_in">module</span>.exports.remove = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">remove</span>(<span class="hljs-params">object, path, value</span>) </span>{ - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { - path = path.split(<span class="hljs-string">"."</span>); +<span class="hljs-keyword">var</span> remove = (<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">remove</span> = <span class="hljs-keyword">function</span> <span class="hljs-title function_">remove</span>(<span class="hljs-params">object, path, value</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> path === <span class="hljs-string">"string"</span>) { + path = path.<span class="hljs-title function_">split</span>(<span class="hljs-string">"."</span>); } - <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) || path.length === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (!(path <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>) || path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } - path = path.slice(); + path = path.<span class="hljs-title function_">slice</span>(); - <span class="hljs-keyword">var</span> key = path.shift(); + <span class="hljs-keyword">var</span> key = path.<span class="hljs-title function_">shift</span>(); - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object !== <span class="hljs-string">"object"</span> || object === <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } - <span class="hljs-keyword">if</span> (path.length === <span class="hljs-number">0</span>) { - <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">Object</span>.hasOwnProperty.call(object, key)) { + <span class="hljs-keyword">if</span> (path.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) { + <span class="hljs-keyword">if</span> (!<span class="hljs-title class_">Object</span>.<span class="hljs-property">hasOwnProperty</span>.<span class="hljs-title function_">call</span>(object, key)) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } <span class="hljs-keyword">delete</span> object[key]; <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>; } <span class="hljs-keyword">else</span> { - <span class="hljs-keyword">return</span> remove(object[key], path, value); + <span class="hljs-keyword">return</span> <span class="hljs-title function_">remove</span>(object[key], path, value); } });</pre></div></div> @@ -314,57 +314,57 @@ <h1>index.js</h1> <li id="section-8"> <div class="annotation"> - <div class="pilwrap "> - <a class="pilcrow" href="#section-8">¶</a> + <div class="sswrap "> + <a class="ss" href="#section-8">§</a> </div> <p><code>deepKeys</code> creates a list of all possible key paths for a given object.</p> <p>The return value is always an array, the members of which are paths in array format. If you want them in dot-notation format, do something like this:</p> -<pre><code class="lang-js">dotty.deepKeys(obj).map(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) </span>{ - <span class="hljs-keyword">return</span> e.join(<span class="hljs-string">"."</span>); +<pre><code class="language-js">dotty.<span class="hljs-title function_">deepKeys</span>(obj).<span class="hljs-title function_">map</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) { + <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">join</span>(<span class="hljs-string">"."</span>); }); </code></pre> <p><em>Note: this will probably explode on recursive objects. Be careful.</em></p> </div> <div class="content"><div class='highlight'><pre> -<span class="hljs-keyword">var</span> deepKeys = (<span class="hljs-built_in">module</span>.exports.deepKeys = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deepKeys</span>(<span class="hljs-params"> +<span class="hljs-keyword">var</span> deepKeys = (<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span>.<span class="hljs-property">deepKeys</span> = <span class="hljs-keyword">function</span> <span class="hljs-title function_">deepKeys</span>(<span class="hljs-params"> object, options, prefix -</span>) </span>{ +</span>) { options = options || {}; - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> prefix === <span class="hljs-string">"undefined"</span>) { + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> prefix === <span class="hljs-string">"undefined"</span>) { prefix = []; } <span class="hljs-keyword">var</span> keys = []; <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> k <span class="hljs-keyword">in</span> object) { - <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">Object</span>.hasOwnProperty.call(object, k)) { + <span class="hljs-keyword">if</span> (!<span class="hljs-title class_">Object</span>.<span class="hljs-property">hasOwnProperty</span>.<span class="hljs-title function_">call</span>(object, k)) { <span class="hljs-keyword">continue</span>; } - <span class="hljs-keyword">if</span> (!options.leavesOnly || <span class="hljs-keyword">typeof</span> object[k] !== <span class="hljs-string">"object"</span>) { - keys.push(prefix.concat([k])); + <span class="hljs-keyword">if</span> (!options.<span class="hljs-property">leavesOnly</span> || <span class="hljs-keyword">typeof</span> object[k] !== <span class="hljs-string">"object"</span>) { + keys.<span class="hljs-title function_">push</span>(prefix.<span class="hljs-title function_">concat</span>([k])); } - <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object[k] === <span class="hljs-string">"object"</span> && object[k] !== <span class="hljs-literal">null</span>) { - keys = keys.concat( - deepKeys( + <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object[k] === <span class="hljs-string">"object"</span> && object[k] !== <span class="hljs-literal">null</span>) { + keys = keys.<span class="hljs-title function_">concat</span>( + <span class="hljs-title function_">deepKeys</span>( object[k], - { <span class="hljs-attr">leavesOnly</span>: options.leavesOnly }, - prefix.concat([k]) + { <span class="hljs-attr">leavesOnly</span>: options.<span class="hljs-property">leavesOnly</span> }, + prefix.<span class="hljs-title function_">concat</span>([k]) ) ); } } - <span class="hljs-keyword">if</span> (options.asStrings) { - keys = keys.map(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">e</span>) </span>{ - <span class="hljs-keyword">return</span> e.join(<span class="hljs-string">"."</span>); + <span class="hljs-keyword">if</span> (options.<span class="hljs-property">asStrings</span>) { + keys = keys.<span class="hljs-title function_">map</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">e</span>) { + <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">join</span>(<span class="hljs-string">"."</span>); }); }
docs/public/fonts/roboto-black.eot+0 −0 modifieddocs/public/fonts/roboto-black.ttf+0 −0 modifieddocs/public/fonts/roboto-black.woff+0 −0 modified.DS_Store+0 −0 removed.github/workflows/main.yml+2 −3 modified@@ -5,17 +5,16 @@ on: branches: - main - master - jobs: build: runs-on: ubuntu-latest strategy: matrix: - node-version: [6.x, 8.x] + node-version: [10.x, 12.x, 14.x, 16.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm install
lib/index.js+3 −1 modified@@ -170,7 +170,7 @@ var put = (module.exports.put = function put(object, path, value) { path = path.slice(); - var key = path.shift(); + var key = "" + path.shift(); if (typeof object !== "object" || object === null || key === "__proto__") { return false; @@ -188,6 +188,8 @@ var put = (module.exports.put = function put(object, path, value) { return put(object[key], path, value); } + + return true; }); //
package.json+2 −2 modified@@ -21,7 +21,7 @@ "author": "Conrad Pankoff <deoxxa@fknsrs.biz> (http://www.fknsrs.biz/)", "license": "BSD-3-Clause", "devDependencies": { - "vows": "^0.8.0", - "docco": "^0.8.0" + "vows": "^0.8.3", + "docco": "^0.8.1" } }
package-lock.json+96 −79 modified@@ -4,22 +4,44 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "diff": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.8.tgz", - "integrity": "sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "docco": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/docco/-/docco-0.8.0.tgz", - "integrity": "sha512-QcWBDnnGaT+rgC0wqynznXv0/4hd6nAFdWNs2fN4FvkH2yAnCYVeRU7GIZXNCeUQ955Lufq+TmZcSXiBa1cGQQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/docco/-/docco-0.8.1.tgz", + "integrity": "sha512-OFVdjpxw4aTI+FThrCY2NEWZV/nvGDFlfeQxUTMkKL+oY2gD2sMl0N5ogoAj3YLZU05UDBSh64ROYzLFzxSoSQ==", "dev": true, "requires": { "commander": ">= 0.5.2", @@ -36,94 +58,89 @@ "dev": true }, "fs-extra": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", - "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, "glob": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.0.6.tgz", - "integrity": "sha1-aVxQvdTi+1xdNwsJHziNNwfikac=", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { - "graceful-fs": "^3.0.2", + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^1.0.0", - "once": "^1.3.0" - }, - "dependencies": { - "graceful-fs": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", - "dev": true, - "requires": { - "natives": "^1.1.0" - } - } + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, "highlight.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.5.0.tgz", - "integrity": "sha512-xTmvd9HiIHR6L53TMC7TKolEj65zG1XU+Onr8oi86mYa+nLcIbxTTWkpW7CsEwv/vK7u1zb8alZIMLDqqN6KTw==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.3.1.tgz", + "integrity": "sha512-PUhCRnPjLtiLHZAQ5A/Dt5F8cWZeMyj9KRsACsWT+OD6OP0x6dp5OmT5jdx0JgEyPxPZZIPQpRN2TciUT7occw==", "dev": true }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, "marked": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.7.tgz", - "integrity": "sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.8.tgz", + "integrity": "sha512-0gVrAjo5m0VZSJb4rpL59K1unJAMb/hm8HRXqasD8VeC8m91ytDPMritgFSlKonfdt+rRYYpP/JfLxgIX8yoSw==", "dev": true }, "minimatch": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz", - "integrity": "sha1-4N0hILSeG3JM6NcUxSCCKpQ4V20=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "brace-expansion": "^1.1.7" } }, - "natives": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.1.tgz", - "integrity": "sha512-8eRaxn8u/4wN8tGkhlc2cgwwvOLMLUMUn4IYTexMgWd+LyUDfeXVkk2ygQR0hvIHbJQXgHujia3ieUUDwNGkEA==", - "dev": true - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -133,33 +150,33 @@ "wrappy": "1" } }, - "sigmund": { + "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, "vows": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.1.tgz", - "integrity": "sha1-4J6YjOWUygWgjXKrzKNOiNtVkTE=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.3.tgz", + "integrity": "sha512-PVIxa/ovXhrw5gA3mz6M+ZF3PHlqX4tutR2p/y9NWPAaFVKcWBE8b2ktfr0opQM/qFmcOVWKjSCJVjnYOvjXhw==", "dev": true, "requires": { - "diff": "~1.0.8", + "diff": "^4.0.1", "eyes": "~0.1.6", - "glob": "~4.0.6" + "glob": "^7.1.2" } }, "wrappy": {
test/put-test.js+9 −0 modified@@ -26,6 +26,15 @@ vows assert.equal(res.a, "b"); }, }, + "returns true": { + topic: (function () { + var res = dotty.put({}, ["a"], "b"); + return res; + })(), + "should set the correct value": function (res) { + assert.equal(res, true); + }, + }, }, "A two-level path": { "as a string": {
test/security-test.js+26 −3 modified@@ -1,4 +1,4 @@ -var dotty = require("../lib/index"), +const dotty = require("../lib/index"), vows = require("vows"), assert = require("assert"); @@ -7,17 +7,40 @@ vows .addBatch({ "When we attempt to update the prototype": { topic() { - var obj = {}; + const obj = {}; dotty.put(obj, "__proto__.polluted", "Muhahahaha"); return obj; }, "it should not update": function (res) { assert.equal(res.polluted, undefined); + assert.equal(Object.prototype.polluted, undefined); + }, + }, + "When we attempt to update the prototype using an array": { + topic() { + const obj = {}; + dotty.put(obj, ["__proto__", "polluted"], "Muhahahaha"); + return obj; + }, + "it should not update": function (res) { + assert.equal(res.polluted, undefined); + assert.equal(Object.prototype.polluted, undefined); + }, + }, + "When we attempt to update the prototype using a non-string": { + topic() { + const obj = {}; + dotty.put(obj, [["__proto__"], "polluted"], "Muhahahaha"); + return obj; + }, + "it should not update": function (res) { + assert.equal(res.polluted, undefined); + assert.equal(Object.prototype.polluted, undefined); }, }, "When we attempt to update the constructor prototype": { topic() { - var obj = {}; + const obj = {}; dotty.put(obj, "constructor.prototype.polluted", "Muhahahaha"); return obj; },
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-6g47-63mv-qpghghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-23624ghsaADVISORY
- github.com/deoxxa/dotty/commit/88f61860dcc274a07a263c32cbe9d44c24ef02d7ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JS-DOTTY-1577292ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.