CVE-2023-38894
Description
Prototype pollution in tree-kit's extend function allows remote code execution via crafted input.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Prototype pollution in tree-kit's extend function allows remote code execution via crafted input.
A prototype pollution vulnerability exists in the extend function of the tree-kit npm package (versions before 0.7.5) when the unflat option is enabled [1][2]. This flaw allows an attacker to pollute the prototype of Object.prototype by injecting properties through a crafted object passed to the function [2].
Exploitation occurs when an attacker-controlled object, such as JSON data parsed by the application, is used as the source argument in treekit.extend({unflat: true}, target, source). For example, passing {'constructor.prototype.polluted': true} can set {}.polluted to true [2]. No authentication is required if the application exposes this functionality to untrusted input.
The impact includes remote code execution (RCE), denial of service via overridden built-in functions like toString, privilege escalation, and cross-site scripting (XSS) [2]. The vulnerability was discovered by Peter Samarin using Jazzer.js as part of OSS-Fuzz [2].
The maintainer released a fix in version 0.7.5, which is available via the commit [4]. Users are strongly advised to upgrade to version 0.7.5 or later to mitigate the risk [2][4].
AI Insight generated on May 20, 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 |
|---|---|---|
tree-kitnpm | < 0.7.5 | 0.7.5 |
Affected products
2- Cronvel/Tree-kitdescription
Patches
161bf10cf0dbdFix prototype pollution in .extend() when the 'unflat' option is set
12 files changed · +471 −269
browser/tree-kit.js+164 −132 modified@@ -205,7 +205,7 @@ function toPathArray( path ) { if ( ! path ) { return EMPTY_PATH ; } if ( typeof path === 'string' ) { - return path[ path.length - 1 ] === '.' ? path.slice( 0 , -1 ).split( '.' ) : path.split( '.' ) ; + return path[ path.length - 1 ] === '.' ? path.slice( 0 , - 1 ).split( '.' ) : path.split( '.' ) ; } throw new TypeError( '[tree.dotPath]: the path argument should be a string or an array' ) ; @@ -332,7 +332,7 @@ dotPath.dec = ( object , path , value ) => { var pointer = pave( object , pathArray ) ; if ( typeof pointer[ key ] === 'number' ) { pointer[ key ] -- ; } - else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = -1 ; } + else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = - 1 ; } return value ; } ; @@ -393,7 +393,7 @@ dotPath.delete = ( object , path ) => { if ( typeof key === 'object' || key === '__proto__' ) { throw new Error( PROTO_POLLUTION_MESSAGE ) ; } - var pointer = walk( object , pathArray , -1 ) ; + var pointer = walk( object , pathArray , - 1 ) ; if ( ! pointer || typeof pointer !== 'object' ) { return false ; } @@ -620,10 +620,7 @@ module.exports = extend ; function extendOne( runtime , options , target , source , mask ) { - var j , jmax , path , - sourceKeys , sourceKey , sourceValue , sourceValueIsObject , sourceValueProto , sourceDescriptor , - targetKey , targetPointer , targetValue , targetValueIsObject , - indexOfSource = -1 ; + var sourceKeys , sourceKey ; // Max depth check if ( options.maxDepth && runtime.depth > options.maxDepth ) { @@ -636,158 +633,193 @@ function extendOne( runtime , options , target , source , mask ) { runtime.references.targets.push( target ) ; } - if ( options.own ) { + // 'unflat' mode computing + if ( options.unflat && runtime.depth === 0 ) { + for ( sourceKey in source ) { + runtime.unflatKeys = sourceKey.split( options.unflat ) ; + runtime.unflatIndex = 0 ; + runtime.unflatFullKey = sourceKey ; + extendOneKV( runtime , options , target , source , runtime.unflatKeys[ runtime.unflatIndex ] , mask ) ; + } + + delete runtime.unflatKeys ; + delete runtime.unflatIndex ; + delete runtime.unflatFullKey ; + } + else if ( options.own ) { if ( options.nonEnum ) { sourceKeys = Object.getOwnPropertyNames( source ) ; } else { sourceKeys = Object.keys( source ) ; } + + for ( sourceKey of sourceKeys ) { + extendOneKV( runtime , options , target , source , sourceKey , mask ) ; + } } - else { sourceKeys = source ; } + else { + for ( sourceKey in source ) { + extendOneKV( runtime , options , target , source , sourceKey , mask ) ; + } + } +} - for ( sourceKey in sourceKeys ) { - if ( options.own ) { sourceKey = sourceKeys[ sourceKey ] ; } - // OMG, this DEPRECATED __proto__ shit is still alive and can be used to hack anything >< - if ( sourceKey === '__proto__' ) { continue ; } - // If descriptor is on, get it now - if ( options.descriptor ) { - sourceDescriptor = Object.getOwnPropertyDescriptor( source , sourceKey ) ; - sourceValue = sourceDescriptor.value ; +function extendOneKV( runtime , options , target , source , sourceKey , mask ) { + // OMG, this DEPRECATED __proto__ shit is still alive and can be used to hack anything >< + if ( sourceKey === '__proto__' ) { return ; } + + let sourceValue , sourceDescriptor , sourceValueProto ; + + if ( runtime.unflatKeys ) { + if ( runtime.unflatIndex < runtime.unflatKeys.length - 1 ) { + sourceValue = {} ; } else { - // We have to trigger an eventual getter only once - sourceValue = source[ sourceKey ] ; + sourceValue = source[ runtime.unflatFullKey ] ; } + } + else if ( options.descriptor ) { + // If descriptor is on, get it now + sourceDescriptor = Object.getOwnPropertyDescriptor( source , sourceKey ) ; + sourceValue = sourceDescriptor.value ; + } + else { + // We have to trigger an eventual getter only once + sourceValue = source[ sourceKey ] ; + } - targetPointer = target ; - targetKey = runtime.prefix + sourceKey ; - - // Do not copy if property is a function and we don't want them - if ( options.nofunc && typeof sourceValue === 'function' ) { continue ; } - - // 'unflat' mode computing - if ( options.unflat && runtime.depth === 0 ) { - path = sourceKey.split( options.unflat ) ; - jmax = path.length - 1 ; + let targetKey = runtime.prefix + sourceKey ; + + // Do not copy if property is a function and we don't want them + if ( options.nofunc && typeof sourceValue === 'function' ) { return ; } + + // Again, trigger an eventual getter only once + let targetValue = target[ targetKey ] ; + let targetValueIsObject = targetValue && ( typeof targetValue === 'object' || typeof targetValue === 'function' ) ; + let sourceValueIsObject = sourceValue && ( typeof sourceValue === 'object' || typeof sourceValue === 'function' ) ; + + if ( + ( options.deep || runtime.unflatKeys ) + && sourceValue + && ( typeof sourceValue === 'object' || ( options.deepFunc && typeof sourceValue === 'function' ) ) + && ( ! options.descriptor || ! sourceDescriptor.get ) + // not a condition we just cache sourceValueProto now... ok it's trashy >< + && ( ( sourceValueProto = Object.getPrototypeOf( sourceValue ) ) || true ) + && ( ! ( options.deep instanceof Set ) || options.deep.has( sourceValueProto ) ) + && ( ! options.immutables || ! options.immutables.has( sourceValueProto ) ) + && ( ! options.preserve || targetValueIsObject ) + && ( ! mask || targetValueIsObject ) + ) { + let indexOfSource = options.circular ? runtime.references.sources.indexOf( sourceValue ) : - 1 ; + + if ( options.flat ) { + // No circular references reconnection when in 'flat' mode + if ( indexOfSource >= 0 ) { return ; } + + extendOne( + { + depth: runtime.depth + 1 , + prefix: runtime.prefix + sourceKey + options.flat , + references: runtime.references + } , + options , target , sourceValue , mask + ) ; + } + else { + if ( indexOfSource >= 0 ) { + // Circular references reconnection... + targetValue = runtime.references.targets[ indexOfSource ] ; + + if ( options.descriptor ) { + Object.defineProperty( target , targetKey , { + value: targetValue , + enumerable: sourceDescriptor.enumerable , + writable: sourceDescriptor.writable , + configurable: sourceDescriptor.configurable + } ) ; + } + else { + target[ targetKey ] = targetValue ; + } - if ( jmax ) { - for ( j = 0 ; j < jmax ; j ++ ) { - if ( ! targetPointer[ path[ j ] ] || - ( typeof targetPointer[ path[ j ] ] !== 'object' && - typeof targetPointer[ path[ j ] ] !== 'function' ) ) { - targetPointer[ path[ j ] ] = {} ; - } + return ; + } - targetPointer = targetPointer[ path[ j ] ] ; + if ( ! targetValueIsObject || ! Object.prototype.hasOwnProperty.call( target , targetKey ) ) { + if ( Array.isArray( sourceValue ) ) { targetValue = [] ; } + else if ( options.proto ) { targetValue = Object.create( sourceValueProto ) ; } + else if ( options.inherit ) { targetValue = Object.create( sourceValue ) ; } + else { targetValue = {} ; } + + if ( options.descriptor ) { + Object.defineProperty( target , targetKey , { + value: targetValue , + enumerable: sourceDescriptor.enumerable , + writable: sourceDescriptor.writable , + configurable: sourceDescriptor.configurable + } ) ; + } + else { + target[ targetKey ] = targetValue ; } - - targetKey = runtime.prefix + path[ jmax ] ; } - } + else if ( options.proto && Object.getPrototypeOf( targetValue ) !== sourceValueProto ) { + Object.setPrototypeOf( targetValue , sourceValueProto ) ; + } + else if ( options.inherit && Object.getPrototypeOf( targetValue ) !== sourceValue ) { + Object.setPrototypeOf( targetValue , sourceValue ) ; + } - // Again, trigger an eventual getter only once - targetValue = targetPointer[ targetKey ] ; - targetValueIsObject = targetValue && ( typeof targetValue === 'object' || typeof targetValue === 'function' ) ; - sourceValueIsObject = sourceValue && ( typeof sourceValue === 'object' || typeof sourceValue === 'function' ) ; - - - if ( options.deep // eslint-disable-line no-constant-condition - && sourceValue - && ( typeof sourceValue === 'object' || ( options.deepFunc && typeof sourceValue === 'function' ) ) - && ( ! options.descriptor || ! sourceDescriptor.get ) - // not a condition we just cache sourceValueProto now... ok it's trashy >< - && ( ( sourceValueProto = Object.getPrototypeOf( sourceValue ) ) || true ) - && ( ! ( options.deep instanceof Set ) || options.deep.has( sourceValueProto ) ) - && ( ! options.immutables || ! options.immutables.has( sourceValueProto ) ) - && ( ! options.preserve || targetValueIsObject ) - && ( ! mask || targetValueIsObject ) - ) { if ( options.circular ) { - indexOfSource = runtime.references.sources.indexOf( sourceValue ) ; + runtime.references.sources.push( sourceValue ) ; + runtime.references.targets.push( targetValue ) ; } - if ( options.flat ) { - // No circular references reconnection when in 'flat' mode - if ( indexOfSource >= 0 ) { continue ; } - - extendOne( - { depth: runtime.depth + 1 , prefix: runtime.prefix + sourceKey + options.flat , references: runtime.references } , - options , targetPointer , sourceValue , mask + if ( runtime.unflatKeys && runtime.unflatIndex < runtime.unflatKeys.length - 1 ) { + // Finish unflatting this property + let nextSourceKey = runtime.unflatKeys[ runtime.unflatIndex + 1 ] ; + + extendOneKV( + { + depth: runtime.depth , + unflatKeys: runtime.unflatKeys , + unflatIndex: runtime.unflatIndex + 1 , + unflatFullKey: runtime.unflatFullKey , + unflatValue: runtime.unflatValue , + prefix: '' , + references: runtime.references + } , + options , targetValue , source , nextSourceKey , mask ) ; } else { - if ( indexOfSource >= 0 ) { - // Circular references reconnection... - targetValue = runtime.references.targets[ indexOfSource ] ; - - if ( options.descriptor ) { - Object.defineProperty( targetPointer , targetKey , { - value: targetValue , - enumerable: sourceDescriptor.enumerable , - writable: sourceDescriptor.writable , - configurable: sourceDescriptor.configurable - } ) ; - } - else { - targetPointer[ targetKey ] = targetValue ; - } - - continue ; - } - - if ( ! targetValueIsObject || ! Object.prototype.hasOwnProperty.call( targetPointer , targetKey ) ) { - if ( Array.isArray( sourceValue ) ) { targetValue = [] ; } - else if ( options.proto ) { targetValue = Object.create( sourceValueProto ) ; } // jshint ignore:line - else if ( options.inherit ) { targetValue = Object.create( sourceValue ) ; } - else { targetValue = {} ; } - - if ( options.descriptor ) { - Object.defineProperty( targetPointer , targetKey , { - value: targetValue , - enumerable: sourceDescriptor.enumerable , - writable: sourceDescriptor.writable , - configurable: sourceDescriptor.configurable - } ) ; - } - else { - targetPointer[ targetKey ] = targetValue ; - } - } - else if ( options.proto && Object.getPrototypeOf( targetValue ) !== sourceValueProto ) { - Object.setPrototypeOf( targetValue , sourceValueProto ) ; - } - else if ( options.inherit && Object.getPrototypeOf( targetValue ) !== sourceValue ) { - Object.setPrototypeOf( targetValue , sourceValue ) ; - } - - if ( options.circular ) { - runtime.references.sources.push( sourceValue ) ; - runtime.references.targets.push( targetValue ) ; - } - // Recursively extends sub-object extendOne( - { depth: runtime.depth + 1 , prefix: '' , references: runtime.references } , + { + depth: runtime.depth + 1 , + prefix: '' , + references: runtime.references + } , options , targetValue , sourceValue , mask ) ; } } - else if ( mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) { - // Do not create new value, and so do not delete source's properties that were not moved. - // We also do not overwrite object with non-object, and we don't overwrite non-object with object (preserve hierarchy) - continue ; - } - else if ( options.preserve && targetValue !== undefined ) { - // Do not overwrite, and so do not delete source's properties that were not moved - continue ; - } - else if ( ! options.inherit ) { - if ( options.descriptor ) { Object.defineProperty( targetPointer , targetKey , sourceDescriptor ) ; } - else { targetPointer[ targetKey ] = targetValue = sourceValue ; } - } - - // Delete owned property of the source object - if ( options.move ) { delete source[ sourceKey ] ; } } + else if ( mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) { + // Do not create new value, and so do not delete source's properties that were not moved. + // We also do not overwrite object with non-object, and we don't overwrite non-object with object (preserve hierarchy) + return ; + } + else if ( options.preserve && targetValue !== undefined ) { + // Do not overwrite, and so do not delete source's properties that were not moved + return ; + } + else if ( ! options.inherit ) { + if ( options.descriptor ) { Object.defineProperty( target , targetKey , sourceDescriptor ) ; } + else { target[ targetKey ] = targetValue = sourceValue ; } + } + + // Delete owned property of the source object + if ( options.move ) { delete source[ sourceKey ] ; } } @@ -1009,7 +1041,7 @@ treePath.op = function( type , object , path , value ) { return pointer[ key ] ; case 'dec' : if ( typeof pointer[ key ] === 'number' ) { pointer[ key ] -- ; } - else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = -1 ; } + else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = - 1 ; } return pointer[ key ] ; case 'append' : if ( ! pointer[ key ] ) { pointer[ key ] = [ value ] ; }
browser/tree-kit.min.js+1 −1 modified@@ -1 +1 @@ -(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.treeKit=e()}})(function(){var e,t,r;return function(){function e(t,r,n){function i(f,u){if(!r[f]){if(!t[f]){var a="function"==typeof require&&require;if(!u&&a)return a(f,!0);if(o)return o(f,!0);var s=new Error("Cannot find module '"+f+"'");throw s.code="MODULE_NOT_FOUND",s}var c=r[f]={exports:{}};t[f][0].call(c.exports,function(e){var r=t[f][1][e];return i(r||e)},c,c.exports,e,t,r,n)}return r[f].exports}for(var o="function"==typeof require&&require,f=0;f<n.length;f++)i(n[f]);return i}return e}()({1:[function(e,t,r){"use strict";const n={};t.exports=n;n.extend=e("./extend.js");n.clone=e("./clone.js");n.path=e("./path.js");n.dotPath=e("./dotPath.js")},{"./clone.js":2,"./dotPath.js":3,"./extend.js":4,"./path.js":5}],2:[function(e,t,r){"use strict";function n(e,t){var r=Object.getPrototypeOf(e);if(n.opaque.has(r)){return n.opaque.get(r)(e)}var i,o,f,u,a,s,c=[{source:e,target:Array.isArray(e)?[]:Object.create(r)}],p=c[0].target,d=new Map;d.set(e,p);while(u=c.shift()){f=Object.getOwnPropertyNames(u.source);for(i=0;i<f.length;i++){o=Object.getOwnPropertyDescriptor(u.source,f[i]);if(!o.value||typeof o.value!=="object"){Object.defineProperty(u.target,f[i],o);continue}a=o.value;if(t){if(d.has(a)){o.value=d.get(a);Object.defineProperty(u.target,f[i],o);continue}}s=Object.getPrototypeOf(o.value);if(n.opaque.has(s)){o.value=n.opaque.get(s)(o.value);Object.defineProperty(u.target,f[i],o);continue}o.value=Array.isArray(a)?[]:Object.create(s);if(t){d.set(a,o.value)}Object.defineProperty(u.target,f[i],o);c.push({source:a,target:o.value})}}return p}t.exports=n;n.opaque=new Map;n.opaque.set(Date.prototype,e=>new Date(e))},{}],3:[function(e,t,r){"use strict";const n={};t.exports=n;const i=[];const o="This would cause prototype pollution";function f(e){if(Array.isArray(e)){return e}if(!e){return i}if(typeof e==="string"){return e[e.length-1]==="."?e.slice(0,-1).split("."):e.split(".")}throw new TypeError("[tree.dotPath]: the path argument should be a string or an array")}function u(e,t,r=0){var n,i,f,u=e;for(n=0,i=t.length+r;n<i;n++){f=t[n];if(typeof f==="object"||f==="__proto__"||typeof u==="function"){throw new Error(o)}if(!u||typeof u!=="object"){return undefined}u=u[f]}return u}function a(e,t){var r,n,i,f=e;for(r=0,n=t.length-1;r<n;r++){i=t[r];if(typeof i==="object"||i==="__proto__"||typeof f[i]==="function"){throw new Error(o)}if(!f[i]||typeof f[i]!=="object"){f[i]={}}f=f[i]}return f}n.get=((e,t)=>u(e,f(t)));n.set=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);u[i]=r;return r});n.define=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(!(i in u)){u[i]=r}return r});n.inc=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(typeof u[i]==="number"){u[i]++}else if(!u[i]||typeof u[i]!=="object"){u[i]=1}return r});n.dec=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(typeof u[i]==="number"){u[i]--}else if(!u[i]||typeof u[i]!=="object"){u[i]=-1}return r});n.concat=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(!u[i]){u[i]=r}else if(Array.isArray(u[i])&&Array.isArray(r)){u[i]=u[i].concat(r)}return r});n.insert=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(!u[i]){u[i]=r}else if(Array.isArray(u[i])&&Array.isArray(r)){u[i]=r.concat(u[i])}return r});n.delete=((e,t)=>{var r=f(t),n=r[r.length-1];if(typeof n==="object"||n==="__proto__"){throw new Error(o)}var i=u(e,r,-1);if(!i||typeof i!=="object"){return false}return delete i[n]});n.autoPush=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(u[i]===undefined){u[i]=r}else if(Array.isArray(u[i])){u[i].push(r)}else{u[i]=[u[i],r]}return u[i]});n.append=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(!u[i]){u[i]=[r]}else if(Array.isArray(u[i])){u[i].push(r)}return u[i]});n.prepend=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=f(t),i=n[n.length-1];if(typeof i==="object"||i==="__proto__"){throw new Error(o)}var u=a(e,n);if(!u[i]){u[i]=[r]}else if(Array.isArray(u[i])){u[i].unshift(r)}return u[i]})},{}],4:[function(e,t,r){"use strict";function n(e,t,...r){var n,o,f=false,u=r.length;if(!u){return t}if(!e||typeof e!=="object"){e={}}var a={depth:0,prefix:""};if(e.deep){if(Array.isArray(e.deep)){e.deep=new Set(e.deep)}else if(!(e.deep instanceof Set)){e.deep=true}}if(e.immutables){if(Array.isArray(e.immutables)){e.immutables=new Set(e.immutables)}else if(!(e.immutables instanceof Set)){delete e.immutables}}if(!e.maxDepth&&e.deep&&!e.circular){e.maxDepth=100}if(e.deepFunc){e.deep=true}if(e.flat){e.deep=true;e.proto=false;e.inherit=false;e.unflat=false;if(typeof e.flat!=="string"){e.flat="."}}if(e.unflat){e.deep=false;e.proto=false;e.inherit=false;e.flat=false;if(typeof e.unflat!=="string"){e.unflat="."}}if(e.inherit){e.own=true;e.proto=false}else if(e.proto){e.own=true}if(!t||typeof t!=="object"&&typeof t!=="function"){f=true}if(!e.skipRoot&&(e.inherit||e.proto)){for(n=u-1;n>=0;n--){o=r[n];if(o&&(typeof o==="object"||typeof o==="function")){if(e.inherit){if(f){t=Object.create(o)}else{Object.setPrototypeOf(t,o)}}else if(e.proto){if(f){t=Object.create(Object.getPrototypeOf(o))}else{Object.setPrototypeOf(t,Object.getPrototypeOf(o))}}break}}}else if(f){t={}}a.references={sources:[],targets:[]};for(n=0;n<u;n++){o=r[n];if(!o||typeof o!=="object"&&typeof o!=="function"){continue}i(a,e,t,o,e.mask<=n+1)}return t}t.exports=n;function i(e,t,r,n,o){var f,u,a,s,c,p,d,l,y,b,h,j,g,w=-1;if(t.maxDepth&&e.depth>t.maxDepth){throw new Error("[tree] extend(): max depth reached("+t.maxDepth+")")}if(t.circular){e.references.sources.push(n);e.references.targets.push(r)}if(t.own){if(t.nonEnum){s=Object.getOwnPropertyNames(n)}else{s=Object.keys(n)}}else{s=n}for(c in s){if(t.own){c=s[c]}if(c==="__proto__"){continue}if(t.descriptor){y=Object.getOwnPropertyDescriptor(n,c);p=y.value}else{p=n[c]}h=r;b=e.prefix+c;if(t.nofunc&&typeof p==="function"){continue}if(t.unflat&&e.depth===0){a=c.split(t.unflat);u=a.length-1;if(u){for(f=0;f<u;f++){if(!h[a[f]]||typeof h[a[f]]!=="object"&&typeof h[a[f]]!=="function"){h[a[f]]={}}h=h[a[f]]}b=e.prefix+a[u]}}j=h[b];g=j&&(typeof j==="object"||typeof j==="function");d=p&&(typeof p==="object"||typeof p==="function");if(t.deep&&p&&(typeof p==="object"||t.deepFunc&&typeof p==="function")&&(!t.descriptor||!y.get)&&((l=Object.getPrototypeOf(p))||true)&&(!(t.deep instanceof Set)||t.deep.has(l))&&(!t.immutables||!t.immutables.has(l))&&(!t.preserve||g)&&(!o||g)){if(t.circular){w=e.references.sources.indexOf(p)}if(t.flat){if(w>=0){continue}i({depth:e.depth+1,prefix:e.prefix+c+t.flat,references:e.references},t,h,p,o)}else{if(w>=0){j=e.references.targets[w];if(t.descriptor){Object.defineProperty(h,b,{value:j,enumerable:y.enumerable,writable:y.writable,configurable:y.configurable})}else{h[b]=j}continue}if(!g||!Object.prototype.hasOwnProperty.call(h,b)){if(Array.isArray(p)){j=[]}else if(t.proto){j=Object.create(l)}else if(t.inherit){j=Object.create(p)}else{j={}}if(t.descriptor){Object.defineProperty(h,b,{value:j,enumerable:y.enumerable,writable:y.writable,configurable:y.configurable})}else{h[b]=j}}else if(t.proto&&Object.getPrototypeOf(j)!==l){Object.setPrototypeOf(j,l)}else if(t.inherit&&Object.getPrototypeOf(j)!==p){Object.setPrototypeOf(j,p)}if(t.circular){e.references.sources.push(p);e.references.targets.push(j)}i({depth:e.depth+1,prefix:"",references:e.references},t,j,p,o)}}else if(o&&(j===undefined||g||d)){continue}else if(t.preserve&&j!==undefined){continue}else if(!t.inherit){if(t.descriptor){Object.defineProperty(h,b,y)}else{h[b]=j=p}}if(t.move){delete n[c]}}}},{}],5:[function(e,t,r){"use strict";const n={};t.exports=n;const i="This would cause prototype pollution";n.op=function(e,t,r,n){var o,f,u,a,s,c=false,p=false,d,l=true;if(!t||typeof t!=="object"){return}if(typeof r==="string"){if(r){f=r.match(/([.#[\]]|[^.#[\]]+)/g)}else{f=[""]}if(f[0]==="."){f.unshift("")}if(f[f.length-1]==="."){f.push("")}}else if(Array.isArray(r)){f=r;p=true}else{throw new TypeError("[tree.path] ."+e+"(): the path argument should be a string or an array")}switch(e){case"get":case"delete":d=false;break;case"set":case"define":case"inc":case"dec":case"append":case"prepend":case"concat":case"insert":case"autoPush":d=true;break;default:throw new TypeError("[tree.path] .op(): wrong type of operation '"+e+"'")}a=t;u=f.length-1;for(o=0;o<=u;o++){if(p){if(s===undefined){s=f[o];if(typeof s==="object"||s==="__proto__"){throw new Error(i)}continue}if(typeof a[s]==="function"){throw new Error(i)}if(!a[s]||typeof a[s]!=="object"){if(!d){return undefined}a[s]={}}a=a[s];s=f[o];if(typeof s==="object"||s==="__proto__"){throw new Error(i)}continue}else if(f[o]==="."){c=false;if(s===undefined){if(!l){l=true;continue}s=""}if(typeof a[s]==="function"){throw new Error(i)}if(!a[s]||typeof a[s]!=="object"){if(!d){return undefined}a[s]={}}a=a[s];l=true;continue}else if(f[o]==="#"||f[o]==="["){c=true;l=false;if(s===undefined){if(!Array.isArray(a)){return undefined}continue}if(typeof a[s]==="function"){throw new Error(i)}if(!a[s]||!Array.isArray(a[s])){if(!d){return undefined}a[s]=[]}a=a[s];continue}else if(f[o]==="]"){l=false;continue}l=false;if(!c){s=f[o];if(typeof s==="object"||s==="__proto__"){throw new Error(i)}continue}switch(f[o]){case"length":s="length";break;case"first":s=0;break;case"last":s=a.length-1;if(s<0){s=0}break;case"next":if(!d){return undefined}s=a.length;break;case"insert":if(!d){return undefined}a.unshift(undefined);s=0;break;default:s=parseInt(f[o],10)}}switch(e){case"get":return a[s];case"delete":if(c&&typeof s==="number"){a.splice(s,1)}else{delete a[s]}return;case"set":a[s]=n;return a[s];case"define":if(!(s in a)){a[s]=n}return a[s];case"inc":if(typeof a[s]==="number"){a[s]++}else if(!a[s]||typeof a[s]!=="object"){a[s]=1}return a[s];case"dec":if(typeof a[s]==="number"){a[s]--}else if(!a[s]||typeof a[s]!=="object"){a[s]=-1}return a[s];case"append":if(!a[s]){a[s]=[n]}else if(Array.isArray(a[s])){a[s].push(n)}return a[s];case"prepend":if(!a[s]){a[s]=[n]}else if(Array.isArray(a[s])){a[s].unshift(n)}return a[s];case"concat":if(!a[s]){a[s]=n}else if(Array.isArray(a[s])&&Array.isArray(n)){a[s]=a[s].concat(n)}return a[s];case"insert":if(!a[s]){a[s]=n}else if(Array.isArray(a[s])&&Array.isArray(n)){a[s]=n.concat(a[s])}return a[s];case"autoPush":if(a[s]===undefined){a[s]=n}else if(Array.isArray(a[s])){a[s].push(n)}else{a[s]=[a[s],n]}return a[s]}};n.get=n.op.bind(undefined,"get");n.delete=n.op.bind(undefined,"delete");n.set=n.op.bind(undefined,"set");n.define=n.op.bind(undefined,"define");n.inc=n.op.bind(undefined,"inc");n.dec=n.op.bind(undefined,"dec");n.append=n.op.bind(undefined,"append");n.prepend=n.op.bind(undefined,"prepend");n.concat=n.op.bind(undefined,"concat");n.insert=n.op.bind(undefined,"insert");n.autoPush=n.op.bind(undefined,"autoPush");n.prototype={get:function(e){return n.get(this,e)},delete:function(e){return n.delete(this,e)},set:function(e,t){return n.set(this,e,t)},define:function(e,t){return n.define(this,e,t)},inc:function(e,t){return n.inc(this,e,t)},dec:function(e,t){return n.dec(this,e,t)},append:function(e,t){return n.append(this,e,t)},prepend:function(e,t){return n.prepend(this,e,t)},concat:function(e,t){return n.concat(this,e,t)},insert:function(e,t){return n.insert(this,e,t)},autoPush:function(e,t){return n.autoPush(this,e,t)}};n.upgrade=function(e){Object.defineProperties(e,{get:{value:n.op.bind(undefined,"get",e)},delete:{value:n.op.bind(undefined,"delete",e)},set:{value:n.op.bind(undefined,"set",e)},define:{value:n.op.bind(undefined,"define",e)},inc:{value:n.op.bind(undefined,"inc",e)},dec:{value:n.op.bind(undefined,"dec",e)},append:{value:n.op.bind(undefined,"append",e)},prepend:{value:n.op.bind(undefined,"prepend",e)},concat:{value:n.op.bind(undefined,"concat",e)},insert:{value:n.op.bind(undefined,"insert",e)},autoPush:{value:n.op.bind(undefined,"autoPush",e)}})}},{}]},{},[1])(1)}); \ No newline at end of file +(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.treeKit=e()}})(function(){var e,t,r;return function(){function e(t,r,n){function f(o,u){if(!r[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var s=new Error("Cannot find module '"+o+"'");throw s.code="MODULE_NOT_FOUND",s}var p=r[o]={exports:{}};t[o][0].call(p.exports,function(e){var r=t[o][1][e];return f(r||e)},p,p.exports,e,t,r,n)}return r[o].exports}for(var i="function"==typeof require&&require,o=0;o<n.length;o++)f(n[o]);return f}return e}()({1:[function(e,t,r){"use strict";const n={};t.exports=n;n.extend=e("./extend.js");n.clone=e("./clone.js");n.path=e("./path.js");n.dotPath=e("./dotPath.js")},{"./clone.js":2,"./dotPath.js":3,"./extend.js":4,"./path.js":5}],2:[function(e,t,r){"use strict";function n(e,t){var r=Object.getPrototypeOf(e);if(n.opaque.has(r)){return n.opaque.get(r)(e)}var f,i,o,u,a,s,p=[{source:e,target:Array.isArray(e)?[]:Object.create(r)}],c=p[0].target,l=new Map;l.set(e,c);while(u=p.shift()){o=Object.getOwnPropertyNames(u.source);for(f=0;f<o.length;f++){i=Object.getOwnPropertyDescriptor(u.source,o[f]);if(!i.value||typeof i.value!=="object"){Object.defineProperty(u.target,o[f],i);continue}a=i.value;if(t){if(l.has(a)){i.value=l.get(a);Object.defineProperty(u.target,o[f],i);continue}}s=Object.getPrototypeOf(i.value);if(n.opaque.has(s)){i.value=n.opaque.get(s)(i.value);Object.defineProperty(u.target,o[f],i);continue}i.value=Array.isArray(a)?[]:Object.create(s);if(t){l.set(a,i.value)}Object.defineProperty(u.target,o[f],i);p.push({source:a,target:i.value})}}return c}t.exports=n;n.opaque=new Map;n.opaque.set(Date.prototype,e=>new Date(e))},{}],3:[function(e,t,r){"use strict";const n={};t.exports=n;const f=[];const i="This would cause prototype pollution";function o(e){if(Array.isArray(e)){return e}if(!e){return f}if(typeof e==="string"){return e[e.length-1]==="."?e.slice(0,-1).split("."):e.split(".")}throw new TypeError("[tree.dotPath]: the path argument should be a string or an array")}function u(e,t,r=0){var n,f,o,u=e;for(n=0,f=t.length+r;n<f;n++){o=t[n];if(typeof o==="object"||o==="__proto__"||typeof u==="function"){throw new Error(i)}if(!u||typeof u!=="object"){return undefined}u=u[o]}return u}function a(e,t){var r,n,f,o=e;for(r=0,n=t.length-1;r<n;r++){f=t[r];if(typeof f==="object"||f==="__proto__"||typeof o[f]==="function"){throw new Error(i)}if(!o[f]||typeof o[f]!=="object"){o[f]={}}o=o[f]}return o}n.get=((e,t)=>u(e,o(t)));n.set=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);u[f]=r;return r});n.define=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(!(f in u)){u[f]=r}return r});n.inc=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(typeof u[f]==="number"){u[f]++}else if(!u[f]||typeof u[f]!=="object"){u[f]=1}return r});n.dec=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(typeof u[f]==="number"){u[f]--}else if(!u[f]||typeof u[f]!=="object"){u[f]=-1}return r});n.concat=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(!u[f]){u[f]=r}else if(Array.isArray(u[f])&&Array.isArray(r)){u[f]=u[f].concat(r)}return r});n.insert=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(!u[f]){u[f]=r}else if(Array.isArray(u[f])&&Array.isArray(r)){u[f]=r.concat(u[f])}return r});n.delete=((e,t)=>{var r=o(t),n=r[r.length-1];if(typeof n==="object"||n==="__proto__"){throw new Error(i)}var f=u(e,r,-1);if(!f||typeof f!=="object"){return false}return delete f[n]});n.autoPush=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(u[f]===undefined){u[f]=r}else if(Array.isArray(u[f])){u[f].push(r)}else{u[f]=[u[f],r]}return u[f]});n.append=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(!u[f]){u[f]=[r]}else if(Array.isArray(u[f])){u[f].push(r)}return u[f]});n.prepend=((e,t,r)=>{if(!e||typeof e!=="object"){return undefined}var n=o(t),f=n[n.length-1];if(typeof f==="object"||f==="__proto__"){throw new Error(i)}var u=a(e,n);if(!u[f]){u[f]=[r]}else if(Array.isArray(u[f])){u[f].unshift(r)}return u[f]})},{}],4:[function(e,t,r){"use strict";function n(e,t,...r){var n,i,o=false,u=r.length;if(!u){return t}if(!e||typeof e!=="object"){e={}}var a={depth:0,prefix:""};if(e.deep){if(Array.isArray(e.deep)){e.deep=new Set(e.deep)}else if(!(e.deep instanceof Set)){e.deep=true}}if(e.immutables){if(Array.isArray(e.immutables)){e.immutables=new Set(e.immutables)}else if(!(e.immutables instanceof Set)){delete e.immutables}}if(!e.maxDepth&&e.deep&&!e.circular){e.maxDepth=100}if(e.deepFunc){e.deep=true}if(e.flat){e.deep=true;e.proto=false;e.inherit=false;e.unflat=false;if(typeof e.flat!=="string"){e.flat="."}}if(e.unflat){e.deep=false;e.proto=false;e.inherit=false;e.flat=false;if(typeof e.unflat!=="string"){e.unflat="."}}if(e.inherit){e.own=true;e.proto=false}else if(e.proto){e.own=true}if(!t||typeof t!=="object"&&typeof t!=="function"){o=true}if(!e.skipRoot&&(e.inherit||e.proto)){for(n=u-1;n>=0;n--){i=r[n];if(i&&(typeof i==="object"||typeof i==="function")){if(e.inherit){if(o){t=Object.create(i)}else{Object.setPrototypeOf(t,i)}}else if(e.proto){if(o){t=Object.create(Object.getPrototypeOf(i))}else{Object.setPrototypeOf(t,Object.getPrototypeOf(i))}}break}}}else if(o){t={}}a.references={sources:[],targets:[]};for(n=0;n<u;n++){i=r[n];if(!i||typeof i!=="object"&&typeof i!=="function"){continue}f(a,e,t,i,e.mask<=n+1)}return t}t.exports=n;function f(e,t,r,n,f){var o,u;if(t.maxDepth&&e.depth>t.maxDepth){throw new Error("[tree] extend(): max depth reached("+t.maxDepth+")")}if(t.circular){e.references.sources.push(n);e.references.targets.push(r)}if(t.unflat&&e.depth===0){for(u in n){e.unflatKeys=u.split(t.unflat);e.unflatIndex=0;e.unflatFullKey=u;i(e,t,r,n,e.unflatKeys[e.unflatIndex],f)}delete e.unflatKeys;delete e.unflatIndex;delete e.unflatFullKey}else if(t.own){if(t.nonEnum){o=Object.getOwnPropertyNames(n)}else{o=Object.keys(n)}for(u of o){i(e,t,r,n,u,f)}}else{for(u in n){i(e,t,r,n,u,f)}}}function i(e,t,r,n,o,u){if(o==="__proto__"){return}let a,s,p;if(e.unflatKeys){if(e.unflatIndex<e.unflatKeys.length-1){a={}}else{a=n[e.unflatFullKey]}}else if(t.descriptor){s=Object.getOwnPropertyDescriptor(n,o);a=s.value}else{a=n[o]}let c=e.prefix+o;if(t.nofunc&&typeof a==="function"){return}let l=r[c];let d=l&&(typeof l==="object"||typeof l==="function");let y=a&&(typeof a==="object"||typeof a==="function");if((t.deep||e.unflatKeys)&&a&&(typeof a==="object"||t.deepFunc&&typeof a==="function")&&(!t.descriptor||!s.get)&&((p=Object.getPrototypeOf(a))||true)&&(!(t.deep instanceof Set)||t.deep.has(p))&&(!t.immutables||!t.immutables.has(p))&&(!t.preserve||d)&&(!u||d)){let y=t.circular?e.references.sources.indexOf(a):-1;if(t.flat){if(y>=0){return}f({depth:e.depth+1,prefix:e.prefix+o+t.flat,references:e.references},t,r,a,u)}else{if(y>=0){l=e.references.targets[y];if(t.descriptor){Object.defineProperty(r,c,{value:l,enumerable:s.enumerable,writable:s.writable,configurable:s.configurable})}else{r[c]=l}return}if(!d||!Object.prototype.hasOwnProperty.call(r,c)){if(Array.isArray(a)){l=[]}else if(t.proto){l=Object.create(p)}else if(t.inherit){l=Object.create(a)}else{l={}}if(t.descriptor){Object.defineProperty(r,c,{value:l,enumerable:s.enumerable,writable:s.writable,configurable:s.configurable})}else{r[c]=l}}else if(t.proto&&Object.getPrototypeOf(l)!==p){Object.setPrototypeOf(l,p)}else if(t.inherit&&Object.getPrototypeOf(l)!==a){Object.setPrototypeOf(l,a)}if(t.circular){e.references.sources.push(a);e.references.targets.push(l)}if(e.unflatKeys&&e.unflatIndex<e.unflatKeys.length-1){let r=e.unflatKeys[e.unflatIndex+1];i({depth:e.depth,unflatKeys:e.unflatKeys,unflatIndex:e.unflatIndex+1,unflatFullKey:e.unflatFullKey,unflatValue:e.unflatValue,prefix:"",references:e.references},t,l,n,r,u)}else{f({depth:e.depth+1,prefix:"",references:e.references},t,l,a,u)}}}else if(u&&(l===undefined||d||y)){return}else if(t.preserve&&l!==undefined){return}else if(!t.inherit){if(t.descriptor){Object.defineProperty(r,c,s)}else{r[c]=l=a}}if(t.move){delete n[o]}}},{}],5:[function(e,t,r){"use strict";const n={};t.exports=n;const f="This would cause prototype pollution";n.op=function(e,t,r,n){var i,o,u,a,s,p=false,c=false,l,d=true;if(!t||typeof t!=="object"){return}if(typeof r==="string"){if(r){o=r.match(/([.#[\]]|[^.#[\]]+)/g)}else{o=[""]}if(o[0]==="."){o.unshift("")}if(o[o.length-1]==="."){o.push("")}}else if(Array.isArray(r)){o=r;c=true}else{throw new TypeError("[tree.path] ."+e+"(): the path argument should be a string or an array")}switch(e){case"get":case"delete":l=false;break;case"set":case"define":case"inc":case"dec":case"append":case"prepend":case"concat":case"insert":case"autoPush":l=true;break;default:throw new TypeError("[tree.path] .op(): wrong type of operation '"+e+"'")}a=t;u=o.length-1;for(i=0;i<=u;i++){if(c){if(s===undefined){s=o[i];if(typeof s==="object"||s==="__proto__"){throw new Error(f)}continue}if(typeof a[s]==="function"){throw new Error(f)}if(!a[s]||typeof a[s]!=="object"){if(!l){return undefined}a[s]={}}a=a[s];s=o[i];if(typeof s==="object"||s==="__proto__"){throw new Error(f)}continue}else if(o[i]==="."){p=false;if(s===undefined){if(!d){d=true;continue}s=""}if(typeof a[s]==="function"){throw new Error(f)}if(!a[s]||typeof a[s]!=="object"){if(!l){return undefined}a[s]={}}a=a[s];d=true;continue}else if(o[i]==="#"||o[i]==="["){p=true;d=false;if(s===undefined){if(!Array.isArray(a)){return undefined}continue}if(typeof a[s]==="function"){throw new Error(f)}if(!a[s]||!Array.isArray(a[s])){if(!l){return undefined}a[s]=[]}a=a[s];continue}else if(o[i]==="]"){d=false;continue}d=false;if(!p){s=o[i];if(typeof s==="object"||s==="__proto__"){throw new Error(f)}continue}switch(o[i]){case"length":s="length";break;case"first":s=0;break;case"last":s=a.length-1;if(s<0){s=0}break;case"next":if(!l){return undefined}s=a.length;break;case"insert":if(!l){return undefined}a.unshift(undefined);s=0;break;default:s=parseInt(o[i],10)}}switch(e){case"get":return a[s];case"delete":if(p&&typeof s==="number"){a.splice(s,1)}else{delete a[s]}return;case"set":a[s]=n;return a[s];case"define":if(!(s in a)){a[s]=n}return a[s];case"inc":if(typeof a[s]==="number"){a[s]++}else if(!a[s]||typeof a[s]!=="object"){a[s]=1}return a[s];case"dec":if(typeof a[s]==="number"){a[s]--}else if(!a[s]||typeof a[s]!=="object"){a[s]=-1}return a[s];case"append":if(!a[s]){a[s]=[n]}else if(Array.isArray(a[s])){a[s].push(n)}return a[s];case"prepend":if(!a[s]){a[s]=[n]}else if(Array.isArray(a[s])){a[s].unshift(n)}return a[s];case"concat":if(!a[s]){a[s]=n}else if(Array.isArray(a[s])&&Array.isArray(n)){a[s]=a[s].concat(n)}return a[s];case"insert":if(!a[s]){a[s]=n}else if(Array.isArray(a[s])&&Array.isArray(n)){a[s]=n.concat(a[s])}return a[s];case"autoPush":if(a[s]===undefined){a[s]=n}else if(Array.isArray(a[s])){a[s].push(n)}else{a[s]=[a[s],n]}return a[s]}};n.get=n.op.bind(undefined,"get");n.delete=n.op.bind(undefined,"delete");n.set=n.op.bind(undefined,"set");n.define=n.op.bind(undefined,"define");n.inc=n.op.bind(undefined,"inc");n.dec=n.op.bind(undefined,"dec");n.append=n.op.bind(undefined,"append");n.prepend=n.op.bind(undefined,"prepend");n.concat=n.op.bind(undefined,"concat");n.insert=n.op.bind(undefined,"insert");n.autoPush=n.op.bind(undefined,"autoPush");n.prototype={get:function(e){return n.get(this,e)},delete:function(e){return n.delete(this,e)},set:function(e,t){return n.set(this,e,t)},define:function(e,t){return n.define(this,e,t)},inc:function(e,t){return n.inc(this,e,t)},dec:function(e,t){return n.dec(this,e,t)},append:function(e,t){return n.append(this,e,t)},prepend:function(e,t){return n.prepend(this,e,t)},concat:function(e,t){return n.concat(this,e,t)},insert:function(e,t){return n.insert(this,e,t)},autoPush:function(e,t){return n.autoPush(this,e,t)}};n.upgrade=function(e){Object.defineProperties(e,{get:{value:n.op.bind(undefined,"get",e)},delete:{value:n.op.bind(undefined,"delete",e)},set:{value:n.op.bind(undefined,"set",e)},define:{value:n.op.bind(undefined,"define",e)},inc:{value:n.op.bind(undefined,"inc",e)},dec:{value:n.op.bind(undefined,"dec",e)},append:{value:n.op.bind(undefined,"append",e)},prepend:{value:n.op.bind(undefined,"prepend",e)},concat:{value:n.op.bind(undefined,"concat",e)},insert:{value:n.op.bind(undefined,"insert",e)},autoPush:{value:n.op.bind(undefined,"autoPush",e)}})}},{}]},{},[1])(1)}); \ No newline at end of file
CHANGELOG+6 −0 modified@@ -1,4 +1,10 @@ +v0.7.5 +------ + +Fix prototype pollution in .extend() when the 'unflat' option is set + + v0.7.4 ------
.eslintrc.js+5 −3 modified@@ -2,13 +2,15 @@ module.exports = { 'root': true , 'env': { 'browser': true , + 'node': true , 'es6': true , - 'node': true + 'es2022': true } , 'parserOptions': { - 'ecmaVersion': 2020 + 'ecmaVersion': 2022 } , 'extends': [ 'eslint:recommended' ] , + 'ignorePatterns': [ "*.min.js" ] , 'rules': { /* @@ -81,7 +83,7 @@ module.exports = { 'words': true , 'nonwords': true , 'overrides': { - '-': false , + //'-': false , } } ] , 'space-in-parens': [ 'error' , 'always' , {
lib/dotPath.js+3 −3 modified@@ -51,7 +51,7 @@ function toPathArray( path ) { if ( ! path ) { return EMPTY_PATH ; } if ( typeof path === 'string' ) { - return path[ path.length - 1 ] === '.' ? path.slice( 0 , -1 ).split( '.' ) : path.split( '.' ) ; + return path[ path.length - 1 ] === '.' ? path.slice( 0 , - 1 ).split( '.' ) : path.split( '.' ) ; } throw new TypeError( '[tree.dotPath]: the path argument should be a string or an array' ) ; @@ -178,7 +178,7 @@ dotPath.dec = ( object , path , value ) => { var pointer = pave( object , pathArray ) ; if ( typeof pointer[ key ] === 'number' ) { pointer[ key ] -- ; } - else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = -1 ; } + else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = - 1 ; } return value ; } ; @@ -239,7 +239,7 @@ dotPath.delete = ( object , path ) => { if ( typeof key === 'object' || key === '__proto__' ) { throw new Error( PROTO_POLLUTION_MESSAGE ) ; } - var pointer = walk( object , pathArray , -1 ) ; + var pointer = walk( object , pathArray , - 1 ) ; if ( ! pointer || typeof pointer !== 'object' ) { return false ; }
lib/extend.js+160 −128 modified@@ -150,10 +150,7 @@ module.exports = extend ; function extendOne( runtime , options , target , source , mask ) { - var j , jmax , path , - sourceKeys , sourceKey , sourceValue , sourceValueIsObject , sourceValueProto , sourceDescriptor , - targetKey , targetPointer , targetValue , targetValueIsObject , - indexOfSource = -1 ; + var sourceKeys , sourceKey ; // Max depth check if ( options.maxDepth && runtime.depth > options.maxDepth ) { @@ -166,157 +163,192 @@ function extendOne( runtime , options , target , source , mask ) { runtime.references.targets.push( target ) ; } - if ( options.own ) { + // 'unflat' mode computing + if ( options.unflat && runtime.depth === 0 ) { + for ( sourceKey in source ) { + runtime.unflatKeys = sourceKey.split( options.unflat ) ; + runtime.unflatIndex = 0 ; + runtime.unflatFullKey = sourceKey ; + extendOneKV( runtime , options , target , source , runtime.unflatKeys[ runtime.unflatIndex ] , mask ) ; + } + + delete runtime.unflatKeys ; + delete runtime.unflatIndex ; + delete runtime.unflatFullKey ; + } + else if ( options.own ) { if ( options.nonEnum ) { sourceKeys = Object.getOwnPropertyNames( source ) ; } else { sourceKeys = Object.keys( source ) ; } + + for ( sourceKey of sourceKeys ) { + extendOneKV( runtime , options , target , source , sourceKey , mask ) ; + } + } + else { + for ( sourceKey in source ) { + extendOneKV( runtime , options , target , source , sourceKey , mask ) ; + } } - else { sourceKeys = source ; } +} - for ( sourceKey in sourceKeys ) { - if ( options.own ) { sourceKey = sourceKeys[ sourceKey ] ; } - // OMG, this DEPRECATED __proto__ shit is still alive and can be used to hack anything >< - if ( sourceKey === '__proto__' ) { continue ; } - // If descriptor is on, get it now - if ( options.descriptor ) { - sourceDescriptor = Object.getOwnPropertyDescriptor( source , sourceKey ) ; - sourceValue = sourceDescriptor.value ; +function extendOneKV( runtime , options , target , source , sourceKey , mask ) { + // OMG, this DEPRECATED __proto__ shit is still alive and can be used to hack anything >< + if ( sourceKey === '__proto__' ) { return ; } + + let sourceValue , sourceDescriptor , sourceValueProto ; + + if ( runtime.unflatKeys ) { + if ( runtime.unflatIndex < runtime.unflatKeys.length - 1 ) { + sourceValue = {} ; } else { - // We have to trigger an eventual getter only once - sourceValue = source[ sourceKey ] ; + sourceValue = source[ runtime.unflatFullKey ] ; } + } + else if ( options.descriptor ) { + // If descriptor is on, get it now + sourceDescriptor = Object.getOwnPropertyDescriptor( source , sourceKey ) ; + sourceValue = sourceDescriptor.value ; + } + else { + // We have to trigger an eventual getter only once + sourceValue = source[ sourceKey ] ; + } - targetPointer = target ; - targetKey = runtime.prefix + sourceKey ; - - // Do not copy if property is a function and we don't want them - if ( options.nofunc && typeof sourceValue === 'function' ) { continue ; } - - // 'unflat' mode computing - if ( options.unflat && runtime.depth === 0 ) { - path = sourceKey.split( options.unflat ) ; - jmax = path.length - 1 ; + let targetKey = runtime.prefix + sourceKey ; + + // Do not copy if property is a function and we don't want them + if ( options.nofunc && typeof sourceValue === 'function' ) { return ; } + + // Again, trigger an eventual getter only once + let targetValue = target[ targetKey ] ; + let targetValueIsObject = targetValue && ( typeof targetValue === 'object' || typeof targetValue === 'function' ) ; + let sourceValueIsObject = sourceValue && ( typeof sourceValue === 'object' || typeof sourceValue === 'function' ) ; + + if ( + ( options.deep || runtime.unflatKeys ) + && sourceValue + && ( typeof sourceValue === 'object' || ( options.deepFunc && typeof sourceValue === 'function' ) ) + && ( ! options.descriptor || ! sourceDescriptor.get ) + // not a condition we just cache sourceValueProto now... ok it's trashy >< + && ( ( sourceValueProto = Object.getPrototypeOf( sourceValue ) ) || true ) + && ( ! ( options.deep instanceof Set ) || options.deep.has( sourceValueProto ) ) + && ( ! options.immutables || ! options.immutables.has( sourceValueProto ) ) + && ( ! options.preserve || targetValueIsObject ) + && ( ! mask || targetValueIsObject ) + ) { + let indexOfSource = options.circular ? runtime.references.sources.indexOf( sourceValue ) : - 1 ; + + if ( options.flat ) { + // No circular references reconnection when in 'flat' mode + if ( indexOfSource >= 0 ) { return ; } + + extendOne( + { + depth: runtime.depth + 1 , + prefix: runtime.prefix + sourceKey + options.flat , + references: runtime.references + } , + options , target , sourceValue , mask + ) ; + } + else { + if ( indexOfSource >= 0 ) { + // Circular references reconnection... + targetValue = runtime.references.targets[ indexOfSource ] ; + + if ( options.descriptor ) { + Object.defineProperty( target , targetKey , { + value: targetValue , + enumerable: sourceDescriptor.enumerable , + writable: sourceDescriptor.writable , + configurable: sourceDescriptor.configurable + } ) ; + } + else { + target[ targetKey ] = targetValue ; + } - if ( jmax ) { - for ( j = 0 ; j < jmax ; j ++ ) { - if ( ! targetPointer[ path[ j ] ] || - ( typeof targetPointer[ path[ j ] ] !== 'object' && - typeof targetPointer[ path[ j ] ] !== 'function' ) ) { - targetPointer[ path[ j ] ] = {} ; - } + return ; + } - targetPointer = targetPointer[ path[ j ] ] ; + if ( ! targetValueIsObject || ! Object.prototype.hasOwnProperty.call( target , targetKey ) ) { + if ( Array.isArray( sourceValue ) ) { targetValue = [] ; } + else if ( options.proto ) { targetValue = Object.create( sourceValueProto ) ; } + else if ( options.inherit ) { targetValue = Object.create( sourceValue ) ; } + else { targetValue = {} ; } + + if ( options.descriptor ) { + Object.defineProperty( target , targetKey , { + value: targetValue , + enumerable: sourceDescriptor.enumerable , + writable: sourceDescriptor.writable , + configurable: sourceDescriptor.configurable + } ) ; + } + else { + target[ targetKey ] = targetValue ; } - - targetKey = runtime.prefix + path[ jmax ] ; } - } + else if ( options.proto && Object.getPrototypeOf( targetValue ) !== sourceValueProto ) { + Object.setPrototypeOf( targetValue , sourceValueProto ) ; + } + else if ( options.inherit && Object.getPrototypeOf( targetValue ) !== sourceValue ) { + Object.setPrototypeOf( targetValue , sourceValue ) ; + } - // Again, trigger an eventual getter only once - targetValue = targetPointer[ targetKey ] ; - targetValueIsObject = targetValue && ( typeof targetValue === 'object' || typeof targetValue === 'function' ) ; - sourceValueIsObject = sourceValue && ( typeof sourceValue === 'object' || typeof sourceValue === 'function' ) ; - - - if ( options.deep // eslint-disable-line no-constant-condition - && sourceValue - && ( typeof sourceValue === 'object' || ( options.deepFunc && typeof sourceValue === 'function' ) ) - && ( ! options.descriptor || ! sourceDescriptor.get ) - // not a condition we just cache sourceValueProto now... ok it's trashy >< - && ( ( sourceValueProto = Object.getPrototypeOf( sourceValue ) ) || true ) - && ( ! ( options.deep instanceof Set ) || options.deep.has( sourceValueProto ) ) - && ( ! options.immutables || ! options.immutables.has( sourceValueProto ) ) - && ( ! options.preserve || targetValueIsObject ) - && ( ! mask || targetValueIsObject ) - ) { if ( options.circular ) { - indexOfSource = runtime.references.sources.indexOf( sourceValue ) ; + runtime.references.sources.push( sourceValue ) ; + runtime.references.targets.push( targetValue ) ; } - if ( options.flat ) { - // No circular references reconnection when in 'flat' mode - if ( indexOfSource >= 0 ) { continue ; } - - extendOne( - { depth: runtime.depth + 1 , prefix: runtime.prefix + sourceKey + options.flat , references: runtime.references } , - options , targetPointer , sourceValue , mask + if ( runtime.unflatKeys && runtime.unflatIndex < runtime.unflatKeys.length - 1 ) { + // Finish unflatting this property + let nextSourceKey = runtime.unflatKeys[ runtime.unflatIndex + 1 ] ; + + extendOneKV( + { + depth: runtime.depth , + unflatKeys: runtime.unflatKeys , + unflatIndex: runtime.unflatIndex + 1 , + unflatFullKey: runtime.unflatFullKey , + unflatValue: runtime.unflatValue , + prefix: '' , + references: runtime.references + } , + options , targetValue , source , nextSourceKey , mask ) ; } else { - if ( indexOfSource >= 0 ) { - // Circular references reconnection... - targetValue = runtime.references.targets[ indexOfSource ] ; - - if ( options.descriptor ) { - Object.defineProperty( targetPointer , targetKey , { - value: targetValue , - enumerable: sourceDescriptor.enumerable , - writable: sourceDescriptor.writable , - configurable: sourceDescriptor.configurable - } ) ; - } - else { - targetPointer[ targetKey ] = targetValue ; - } - - continue ; - } - - if ( ! targetValueIsObject || ! Object.prototype.hasOwnProperty.call( targetPointer , targetKey ) ) { - if ( Array.isArray( sourceValue ) ) { targetValue = [] ; } - else if ( options.proto ) { targetValue = Object.create( sourceValueProto ) ; } // jshint ignore:line - else if ( options.inherit ) { targetValue = Object.create( sourceValue ) ; } - else { targetValue = {} ; } - - if ( options.descriptor ) { - Object.defineProperty( targetPointer , targetKey , { - value: targetValue , - enumerable: sourceDescriptor.enumerable , - writable: sourceDescriptor.writable , - configurable: sourceDescriptor.configurable - } ) ; - } - else { - targetPointer[ targetKey ] = targetValue ; - } - } - else if ( options.proto && Object.getPrototypeOf( targetValue ) !== sourceValueProto ) { - Object.setPrototypeOf( targetValue , sourceValueProto ) ; - } - else if ( options.inherit && Object.getPrototypeOf( targetValue ) !== sourceValue ) { - Object.setPrototypeOf( targetValue , sourceValue ) ; - } - - if ( options.circular ) { - runtime.references.sources.push( sourceValue ) ; - runtime.references.targets.push( targetValue ) ; - } - // Recursively extends sub-object extendOne( - { depth: runtime.depth + 1 , prefix: '' , references: runtime.references } , + { + depth: runtime.depth + 1 , + prefix: '' , + references: runtime.references + } , options , targetValue , sourceValue , mask ) ; } } - else if ( mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) { - // Do not create new value, and so do not delete source's properties that were not moved. - // We also do not overwrite object with non-object, and we don't overwrite non-object with object (preserve hierarchy) - continue ; - } - else if ( options.preserve && targetValue !== undefined ) { - // Do not overwrite, and so do not delete source's properties that were not moved - continue ; - } - else if ( ! options.inherit ) { - if ( options.descriptor ) { Object.defineProperty( targetPointer , targetKey , sourceDescriptor ) ; } - else { targetPointer[ targetKey ] = targetValue = sourceValue ; } - } - - // Delete owned property of the source object - if ( options.move ) { delete source[ sourceKey ] ; } } + else if ( mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) { + // Do not create new value, and so do not delete source's properties that were not moved. + // We also do not overwrite object with non-object, and we don't overwrite non-object with object (preserve hierarchy) + return ; + } + else if ( options.preserve && targetValue !== undefined ) { + // Do not overwrite, and so do not delete source's properties that were not moved + return ; + } + else if ( ! options.inherit ) { + if ( options.descriptor ) { Object.defineProperty( target , targetKey , sourceDescriptor ) ; } + else { target[ targetKey ] = targetValue = sourceValue ; } + } + + // Delete owned property of the source object + if ( options.move ) { delete source[ sourceKey ] ; } }
lib/path.js+1 −1 modified@@ -215,7 +215,7 @@ treePath.op = function( type , object , path , value ) { return pointer[ key ] ; case 'dec' : if ( typeof pointer[ key ] === 'number' ) { pointer[ key ] -- ; } - else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = -1 ; } + else if ( ! pointer[ key ] || typeof pointer[ key ] !== 'object' ) { pointer[ key ] = - 1 ; } return pointer[ key ] ; case 'append' : if ( ! pointer[ key ] ) { pointer[ key ] = [ value ] ; }
.npmignore+57 −0 added@@ -0,0 +1,57 @@ +# +++ .gitignore +# Specific # +############ + +*.local.* +*.local +*.log +*.html.gz +*.css.gz +*.js.gz +.spellcast +build +_build +_templates +_static + + +# gitignore / Node.gitignore # +############################## +lib-cov +lcov.info +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz + +pids +logs +results +build +.grunt +package-lock.json + +node_modules + + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db + + + +# --- .gitignore +test +log +sample +wfm.json
package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "tree-kit", - "version": "0.7.4", + "version": "0.7.5", "description": "Tree utilities which provides a full-featured extend and object-cloning facility, and various tools to deal with nested object structures.", "main": "lib/tree.js", "directories": {
test/dotPath-test.js+3 −0 modified@@ -611,6 +611,7 @@ describe( "Tree's array dot-path on objects" , () => { describe( ".dotPath() security issues" , () => { it( "Prototype pollution using .__proto__" , () => { + delete Object.prototype.hack ; expect( () => path.set( {} , '__proto__.hack' , 'hacked' ) ).to.throw() ; expect( Object.prototype.hack ).to.be.undefined() ; expect( () => path.set( {} , '__proto__' , 'hacked' ) ).to.throw() ; @@ -620,6 +621,7 @@ describe( ".dotPath() security issues" , () => { } ) ; it( "Prototype pollution using a path array: [['__proto__']]" , () => { + delete Object.prototype.hack ; expect( () => path.set( {} , [['__proto__'],'hack'] , 'hacked' ) ).to.throw() ; expect( Object.prototype.hack ).to.be.undefined() ; expect( () => path.set( {} , '__proto__' , 'hacked' ) ).to.throw() ; @@ -629,6 +631,7 @@ describe( ".dotPath() security issues" , () => { } ) ; it( "Prototype pollution using .constructor" , () => { + delete Object.prototype.hack ; expect( () => path.set( {} , 'constructor.prototype' , 'hacked' ) ).to.throw() ; expect( () => path.set( {} , 'constructor.prototype.hack' , 'hacked' ) ).to.throw() ; expect( Object.prototype.hack ).to.be.undefined() ;
test/extend-test.js+67 −0 modified@@ -816,6 +816,40 @@ describe( "extend()" , () => { it( "with 'unflat' option" , () => { var e , o ; + e = {} ; + extend( { unflat: true } , e , { 'subtree.a': 'value' } ) ; + expect( e ).to.equal( { + subtree: { + a: 'value' , + } + } ) ; + extend( { unflat: true } , e , { 'subtree.b': 'value2' } ) ; + expect( e ).to.equal( { + subtree: { + a: 'value' , + b: 'value2' , + } + } ) ; + extend( { unflat: true } , e , { 'subtree.a': 'replaced' } ) ; + expect( e ).to.equal( { + subtree: { + a: 'replaced' , + b: 'value2' , + } + } ) ; + extend( { unflat: true } , e , { 'subtree2.subtree.c': 'value3' } ) ; + expect( e ).to.equal( { + subtree: { + a: 'replaced' , + b: 'value2' , + } , + subtree2: { + subtree: { + c: 'value3' , + } + } + } ) ; + o = { three: 3 , four: '4' , @@ -1012,6 +1046,39 @@ describe( "extend()" , () => { } ) ; it( "with 'skipRoot' option" ) ; + } ) ; + +describe( ".extend() security issues" , () => { + + it( "Prototype pollution using .__proto__" , () => { + delete Object.prototype.hack ; + var o = {} ; + extend( { deep: true } , o , { __proto__: { prototype: { hack: "hacked" } } } ) ; + expect( Object.prototype.hack ).to.be.undefined() ; + } ) ; + + it( "Prototype pollution using .constructor" , () => { + delete Object.prototype.hack ; + var o = {} ; + extend( { deep: true } , o , { constructor: { prototype: { hack: "hacked" } } } ) ; + expect( Object.prototype.hack ).to.be.undefined() ; + } ) ; + + it( "Prototype pollution using 'unflat' option and using .__proto__" , () => { + delete Object.prototype.hack ; + var o = {} ; + extend( { unflat: true } , o , { "__proto__.hack": "hacked" } ) ; + expect( Object.prototype.hack ).to.be.undefined() ; + } ) ; + + it( "Prototype pollution using 'unflat' option and using .constructor" , () => { + delete Object.prototype.hack ; + var o = {} ; + extend( { unflat: true } , o , { "constructor.prototype.hack": "hacked" } ) ; + expect( Object.prototype.hack ).to.be.undefined() ; + } ) ; +} ) ; +
test/path-test.js+3 −0 modified@@ -940,6 +940,7 @@ describe( "Tree's array path on objects" , function() { describe( ".path() security issues" , () => { it( "Prototype pollution using .__proto__" , () => { + delete Object.prototype.hack ; expect( () => path.set( {} , '__proto__.hack' , 'hacked' ) ).to.throw() ; expect( Object.prototype.hack ).to.be.undefined() ; expect( () => path.set( {} , '__proto__' , 'hacked' ) ).to.throw() ; @@ -949,6 +950,7 @@ describe( ".path() security issues" , () => { } ) ; it( "Prototype pollution using a path array: [['__proto__']]" , () => { + delete Object.prototype.hack ; expect( () => path.set( {} , [['__proto__'],'hack'] , 'hacked' ) ).to.throw() ; expect( Object.prototype.hack ).to.be.undefined() ; expect( () => path.set( {} , '__proto__' , 'hacked' ) ).to.throw() ; @@ -958,6 +960,7 @@ describe( ".path() security issues" , () => { } ) ; it( "Prototype pollution using .constructor" , () => { + delete Object.prototype.hack ; expect( () => path.set( {} , 'constructor.prototype' , 'hacked' ) ).to.throw() ; expect( () => path.set( {} , 'constructor.prototype.hack' , 'hacked' ) ).to.throw() ; expect( Object.prototype.hack ).to.be.undefined() ;
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5News mentions
0No linked articles in our index yet.