--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian....@packages.debian.org
Usertags: pu
[ Reason ]
node-object-path is vulnerable to prototye pollution (CVE-2021-23434 and
CVE-2021-3805
[ Impact ]
Medium vulnerability
[ Tests ]
Test passed with these patches, including new checks
[ Risks ]
Low risk, package is not really different than the one pushed to
unstable (only doc differs).
[ Checklist ]
[X] *all* changes are documented in the d/changelog
[X] I reviewed all changes and I approve them
[X] attach debdiff against the package in (old)stable
[X] the issue is verified as fixed in unstable
[ Changes ]
Better checks
[ Other info ]
Note that we could upload a 0.11.8-1~deb11u1: there is no differences
except a documentation update. If you agree, I prefer this way.
Cheers,
Yadd
diff --git a/debian/changelog b/debian/changelog
index f1e6929..ce9339e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+node-object-path (0.11.5-3+deb11u1) bullseye; urgency=medium
+
+ * Team upload
+ * Fix prototype pollution (Closes: CVE-2021-23434)
+ * Fix prototype pollution (Closes: CVE-2021-3805)
+
+ -- Yadd <y...@debian.org> Fri, 17 Sep 2021 18:38:10 +0200
+
node-object-path (0.11.5-3) unstable; urgency=medium
* Team upload
diff --git a/debian/gbp.conf b/debian/gbp.conf
index b713356..e11bcb5 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,5 +1,6 @@
[DEFAULT]
pristine-tar = True
+debian-branch = bullseye
[import-orig]
filter = [ '.gitignore', '.travis.yml', '.git*' ]
diff --git a/debian/patches/CVE-2021-23434.patch
b/debian/patches/CVE-2021-23434.patch
new file mode 100644
index 0000000..8d08d2e
--- /dev/null
+++ b/debian/patches/CVE-2021-23434.patch
@@ -0,0 +1,67 @@
+Description: Fix prototype pollution when path components are not strings
+Author: Mario Casciaro <mariocasci...@gmail.com
+Origin: upstream, https://github.com/mariocasciaro/object-path/commit/7bdf4abef
+Bug: https://snyk.io/vuln/SNYK-JS-OBJECTPATH-1569453
+Forwarded: not-needed
+Reviewed-By: Yadd <y...@debian.org>
+Last-Update: 2021-09-17
+
+--- a/index.js
++++ b/index.js
+@@ -111,6 +111,9 @@
+ return set(obj, path.split('.').map(getKey), value, doNotReplace);
+ }
+ var currentPath = path[0];
++ if (typeof currentPath !== 'string' && typeof currentPath !== 'number')
{
++ currentPath = String(currentPath)
++ }
+ var currentValue = getShallowProperty(obj, currentPath);
+ if (options.includeInheritedProps && (currentPath === '__proto__' ||
+ (currentPath === 'constructor' && typeof currentValue ===
'function'))) {
+--- a/test.js
++++ b/test.js
+@@ -241,12 +241,18 @@
+ objectPath.set({}, '__proto__.injected', 'this is bad')
+ expect(Object.prototype.injected).to.be.undefined
+
++ objectPath.set({}, [['__proto__'], 'injected'], 'this is bad')
++ expect(Object.prototype.injected).to.be.undefined
++
+ function Clazz() {}
+ Clazz.prototype.test = 'original'
+
+ objectPath.set(new Clazz(), '__proto__.test', 'this is bad')
+ expect(Clazz.prototype.test).to.be.equal('original')
+
++ objectPath.set(new Clazz(), [['__proto__'], 'test'], 'this is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++
+ objectPath.set(new Clazz(), 'constructor.prototype.test', 'this is bad')
+ expect(Clazz.prototype.test).to.be.equal('original')
+ })
+@@ -256,6 +262,11 @@
+ .to.throw('For security reasons')
+ expect(Object.prototype.injected).to.be.undefined
+
++ expect(function() {
++ objectPath.withInheritedProps.set({}, [['__proto__'], 'injected'],
'this is bad')
++ expect(Object.prototype.injected).to.be.undefined
++ }).to.throw('For security reasons')
++
+ function Clazz() {}
+ Clazz.prototype.test = 'original'
+
+@@ -267,8 +278,11 @@
+ .to.throw('For security reasons')
+ expect(Clazz.prototype.test).to.be.equal('original')
+
+- const obj = {}
+- expect(function() {objectPath.withInheritedProps.set(obj,
'constructor.prototype.injected', 'this is OK')})
++ expect(function() {objectPath.withInheritedProps.set({},
'constructor.prototype.injected', 'this is OK')})
++ .to.throw('For security reasons')
++ expect(Object.prototype.injected).to.be.undefined
++
++ expect(function() {objectPath.withInheritedProps.set({},
[['constructor'], 'prototype', 'injected'], 'this is bad')})
+ .to.throw('For security reasons')
+ expect(Object.prototype.injected).to.be.undefined
+ })
diff --git a/debian/patches/CVE-2021-3805.patch
b/debian/patches/CVE-2021-3805.patch
new file mode 100644
index 0000000..daa56ff
--- /dev/null
+++ b/debian/patches/CVE-2021-3805.patch
@@ -0,0 +1,837 @@
+Description: Fix prototype pollution vulnerability
+Author: Mario Casciaro <mariocasci...@gmail.com>
+Origin: upstream, https://github.com/mariocasciaro/object-path/commit/4f0903fd7
+Bug: https://huntr.dev/bounties/571e3baf-7c46-46e3-9003-ba7e4e623053
+Forwarded: not-needed
+Reviewed-By: Yadd <y...@debian.org>
+Last-Update: 2021-09-17
+
+--- a/README.md
++++ b/README.md
+@@ -172,6 +172,8 @@
+ objectPath.set(obj, 'notOwn.prop', 'b');
+ ```
+
++**NOTE**: For security reasons `object-path` will throw an exception when
trying to access an object's magic properties (e.g. `__proto__`, `constructor`)
when in "inherited props" mode.
++
+ ### Immutability
+
+ If you are looking for an *immutable* alternative of this library, you can
take a look at:
[object-path-immutable](https://github.com/mariocasciaro/object-path-immutable)
+--- a/index.js
++++ b/index.js
+@@ -1,87 +1,88 @@
+-(function (root, factory){
+- 'use strict';
++(function (root, factory) {
++ 'use strict'
+
+ /*istanbul ignore next:cant test*/
+ if (typeof module === 'object' && typeof module.exports === 'object') {
+- module.exports = factory();
++ module.exports = factory()
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+- define([], factory);
++ define([], factory)
+ } else {
+ // Browser globals
+- root.objectPath = factory();
++ root.objectPath = factory()
+ }
+-})(this, function(){
+- 'use strict';
++})(this, function () {
++ 'use strict'
+
+- var toStr = Object.prototype.toString;
+- function hasOwnProperty(obj, prop) {
+- if(obj == null) {
++ var toStr = Object.prototype.toString
++
++ function hasOwnProperty (obj, prop) {
++ if (obj == null) {
+ return false
+ }
+ //to handle objects with null prototypes (too edge case?)
+ return Object.prototype.hasOwnProperty.call(obj, prop)
+ }
+
+- function isEmpty(value){
++ function isEmpty (value) {
+ if (!value) {
+- return true;
++ return true
+ }
+ if (isArray(value) && value.length === 0) {
+- return true;
++ return true
+ } else if (typeof value !== 'string') {
+- for (var i in value) {
+- if (hasOwnProperty(value, i)) {
+- return false;
+- }
++ for (var i in value) {
++ if (hasOwnProperty(value, i)) {
++ return false
+ }
+- return true;
++ }
++ return true
+ }
+- return false;
++ return false
+ }
+
+- function toString(type){
+- return toStr.call(type);
++ function toString (type) {
++ return toStr.call(type)
+ }
+
+- function isObject(obj){
+- return typeof obj === 'object' && toString(obj) === "[object Object]";
++ function isObject (obj) {
++ return typeof obj === 'object' && toString(obj) === '[object Object]'
+ }
+
+- var isArray = Array.isArray || function(obj){
++ var isArray = Array.isArray || function (obj) {
+ /*istanbul ignore next:cant test*/
+- return toStr.call(obj) === '[object Array]';
++ return toStr.call(obj) === '[object Array]'
+ }
+
+- function isBoolean(obj){
+- return typeof obj === 'boolean' || toString(obj) === '[object Boolean]';
++ function isBoolean (obj) {
++ return typeof obj === 'boolean' || toString(obj) === '[object Boolean]'
+ }
+
+- function getKey(key){
+- var intKey = parseInt(key);
++ function getKey (key) {
++ var intKey = parseInt(key)
+ if (intKey.toString() === key) {
+- return intKey;
++ return intKey
+ }
+- return key;
++ return key
+ }
+
+- function factory(options) {
++ function factory (options) {
+ options = options || {}
+
+- var objectPath = function(obj) {
+- return Object.keys(objectPath).reduce(function(proxy, prop) {
+- if(prop === 'create') {
+- return proxy;
++ var objectPath = function (obj) {
++ return Object.keys(objectPath).reduce(function (proxy, prop) {
++ if (prop === 'create') {
++ return proxy
+ }
+
+ /*istanbul ignore else*/
+ if (typeof objectPath[prop] === 'function') {
+- proxy[prop] = objectPath[prop].bind(objectPath, obj);
++ proxy[prop] = objectPath[prop].bind(objectPath, obj)
+ }
+
+- return proxy;
+- }, {});
+- };
++ return proxy
++ }, {})
++ }
+
+ var hasShallowProperty
+ if (options.includeInheritedProps) {
+@@ -94,213 +95,226 @@
+ }
+ }
+
+- function getShallowProperty(obj, prop) {
++ function getShallowProperty (obj, prop) {
+ if (hasShallowProperty(obj, prop)) {
+- return obj[prop];
++ return obj[prop]
++ }
++ }
++
++ var getShallowPropertySafely
++ if (options.includeInheritedProps) {
++ getShallowPropertySafely = function (obj, currentPath) {
++ if (typeof currentPath !== 'string' && typeof currentPath !==
'number') {
++ currentPath = String(currentPath)
++ }
++ var currentValue = getShallowProperty(obj, currentPath)
++ if (currentPath === '__proto__' || currentPath === 'prototype' ||
++ (currentPath === 'constructor' && typeof currentValue ===
'function')) {
++ throw new Error('For security reasons, object\'s magic properties
cannot be set')
++ }
++ return currentValue
++ }
++ } else {
++ getShallowPropertySafely = function (obj, currentPath) {
++ return getShallowProperty(obj, currentPath)
+ }
+ }
+
+- function set(obj, path, value, doNotReplace){
++ function set (obj, path, value, doNotReplace) {
+ if (typeof path === 'number') {
+- path = [path];
++ path = [path]
+ }
+ if (!path || path.length === 0) {
+- return obj;
++ return obj
+ }
+ if (typeof path === 'string') {
+- return set(obj, path.split('.').map(getKey), value, doNotReplace);
+- }
+- var currentPath = path[0];
+- if (typeof currentPath !== 'string' && typeof currentPath !== 'number')
{
+- currentPath = String(currentPath)
+- }
+- var currentValue = getShallowProperty(obj, currentPath);
+- if (options.includeInheritedProps && (currentPath === '__proto__' ||
+- (currentPath === 'constructor' && typeof currentValue ===
'function'))) {
+- throw new Error('For security reasons, object\'s magic properties
cannot be set')
++ return set(obj, path.split('.').map(getKey), value, doNotReplace)
+ }
++ var currentPath = path[0]
++ var currentValue = getShallowPropertySafely(obj, currentPath)
+ if (path.length === 1) {
+ if (currentValue === void 0 || !doNotReplace) {
+- obj[currentPath] = value;
++ obj[currentPath] = value
+ }
+- return currentValue;
++ return currentValue
+ }
+
+ if (currentValue === void 0) {
+ //check if we assume an array
+- if(typeof path[1] === 'number') {
+- obj[currentPath] = [];
++ if (typeof path[1] === 'number') {
++ obj[currentPath] = []
+ } else {
+- obj[currentPath] = {};
++ obj[currentPath] = {}
+ }
+ }
+
+- return set(obj[currentPath], path.slice(1), value, doNotReplace);
++ return set(obj[currentPath], path.slice(1), value, doNotReplace)
+ }
+
+ objectPath.has = function (obj, path) {
+ if (typeof path === 'number') {
+- path = [path];
++ path = [path]
+ } else if (typeof path === 'string') {
+- path = path.split('.');
++ path = path.split('.')
+ }
+
+ if (!path || path.length === 0) {
+- return !!obj;
++ return !!obj
+ }
+
+ for (var i = 0; i < path.length; i++) {
+- var j = getKey(path[i]);
++ var j = getKey(path[i])
+
+- if((typeof j === 'number' && isArray(obj) && j < obj.length) ||
++ if ((typeof j === 'number' && isArray(obj) && j < obj.length) ||
+ (options.includeInheritedProps ? (j in Object(obj)) :
hasOwnProperty(obj, j))) {
+- obj = obj[j];
++ obj = obj[j]
+ } else {
+- return false;
++ return false
+ }
+ }
+
+- return true;
+- };
++ return true
++ }
+
+- objectPath.ensureExists = function (obj, path, value){
+- return set(obj, path, value, true);
+- };
++ objectPath.ensureExists = function (obj, path, value) {
++ return set(obj, path, value, true)
++ }
+
+- objectPath.set = function (obj, path, value, doNotReplace){
+- return set(obj, path, value, doNotReplace);
+- };
++ objectPath.set = function (obj, path, value, doNotReplace) {
++ return set(obj, path, value, doNotReplace)
++ }
+
+- objectPath.insert = function (obj, path, value, at){
+- var arr = objectPath.get(obj, path);
+- at = ~~at;
++ objectPath.insert = function (obj, path, value, at) {
++ var arr = objectPath.get(obj, path)
++ at = ~~at
+ if (!isArray(arr)) {
+- arr = [];
+- objectPath.set(obj, path, arr);
++ arr = []
++ objectPath.set(obj, path, arr)
+ }
+- arr.splice(at, 0, value);
+- };
++ arr.splice(at, 0, value)
++ }
+
+- objectPath.empty = function(obj, path) {
++ objectPath.empty = function (obj, path) {
+ if (isEmpty(path)) {
+- return void 0;
++ return void 0
+ }
+ if (obj == null) {
+- return void 0;
++ return void 0
+ }
+
+- var value, i;
++ var value, i
+ if (!(value = objectPath.get(obj, path))) {
+- return void 0;
++ return void 0
+ }
+
+ if (typeof value === 'string') {
+- return objectPath.set(obj, path, '');
++ return objectPath.set(obj, path, '')
+ } else if (isBoolean(value)) {
+- return objectPath.set(obj, path, false);
++ return objectPath.set(obj, path, false)
+ } else if (typeof value === 'number') {
+- return objectPath.set(obj, path, 0);
++ return objectPath.set(obj, path, 0)
+ } else if (isArray(value)) {
+- value.length = 0;
++ value.length = 0
+ } else if (isObject(value)) {
+ for (i in value) {
+ if (hasShallowProperty(value, i)) {
+- delete value[i];
++ delete value[i]
+ }
+ }
+ } else {
+- return objectPath.set(obj, path, null);
++ return objectPath.set(obj, path, null)
+ }
+- };
++ }
+
+- objectPath.push = function (obj, path /*, values */){
+- var arr = objectPath.get(obj, path);
++ objectPath.push = function (obj, path /*, values */) {
++ var arr = objectPath.get(obj, path)
+ if (!isArray(arr)) {
+- arr = [];
+- objectPath.set(obj, path, arr);
++ arr = []
++ objectPath.set(obj, path, arr)
+ }
+
+- arr.push.apply(arr, Array.prototype.slice.call(arguments, 2));
+- };
++ arr.push.apply(arr, Array.prototype.slice.call(arguments, 2))
++ }
+
+ objectPath.coalesce = function (obj, paths, defaultValue) {
+- var value;
++ var value
+
+ for (var i = 0, len = paths.length; i < len; i++) {
+ if ((value = objectPath.get(obj, paths[i])) !== void 0) {
+- return value;
++ return value
+ }
+ }
+
+- return defaultValue;
+- };
++ return defaultValue
++ }
+
+- objectPath.get = function (obj, path, defaultValue){
++ objectPath.get = function (obj, path, defaultValue) {
+ if (typeof path === 'number') {
+- path = [path];
++ path = [path]
+ }
+ if (!path || path.length === 0) {
+- return obj;
++ return obj
+ }
+ if (obj == null) {
+- return defaultValue;
++ return defaultValue
+ }
+ if (typeof path === 'string') {
+- return objectPath.get(obj, path.split('.'), defaultValue);
++ return objectPath.get(obj, path.split('.'), defaultValue)
+ }
+
+- var currentPath = getKey(path[0]);
+- var nextObj = getShallowProperty(obj, currentPath)
++ var currentPath = getKey(path[0])
++ var nextObj = getShallowPropertySafely(obj, currentPath)
+ if (nextObj === void 0) {
+- return defaultValue;
++ return defaultValue
+ }
+
+ if (path.length === 1) {
+- return nextObj;
++ return nextObj
+ }
+
+- return objectPath.get(obj[currentPath], path.slice(1), defaultValue);
+- };
++ return objectPath.get(obj[currentPath], path.slice(1), defaultValue)
++ }
+
+- objectPath.del = function del(obj, path) {
++ objectPath.del = function del (obj, path) {
+ if (typeof path === 'number') {
+- path = [path];
++ path = [path]
+ }
+
+ if (obj == null) {
+- return obj;
++ return obj
+ }
+
+ if (isEmpty(path)) {
+- return obj;
++ return obj
+ }
+- if(typeof path === 'string') {
+- return objectPath.del(obj, path.split('.'));
++ if (typeof path === 'string') {
++ return objectPath.del(obj, path.split('.'))
+ }
+
+- var currentPath = getKey(path[0]);
++ var currentPath = getKey(path[0])
++ getShallowPropertySafely(obj, currentPath)
+ if (!hasShallowProperty(obj, currentPath)) {
+- return obj;
++ return obj
+ }
+
+- if(path.length === 1) {
++ if (path.length === 1) {
+ if (isArray(obj)) {
+- obj.splice(currentPath, 1);
++ obj.splice(currentPath, 1)
+ } else {
+- delete obj[currentPath];
++ delete obj[currentPath]
+ }
+ } else {
+- return objectPath.del(obj[currentPath], path.slice(1));
++ return objectPath.del(obj[currentPath], path.slice(1))
+ }
+
+- return obj;
++ return obj
+ }
+
+- return objectPath;
++ return objectPath
+ }
+
+- var mod = factory();
+- mod.create = factory;
++ var mod = factory()
++ mod.create = factory
+ mod.withInheritedProps = factory({includeInheritedProps: true})
+- return mod;
+-});
++ return mod
++})
+--- a/test.js
++++ b/test.js
+@@ -133,6 +133,43 @@
+ expect(objectPath.get(extended, 'enabled')).to.be.equal(true)
+ expect(objectPath.get(extended, 'one')).to.be.equal(undefined)
+ })
++
++ it('[security] should not get magic properties in default mode', function
() {
++ expect(objectPath.get({}, '__proto__')).to.be.undefined
++ expect(objectPath.get({}, [['__proto__']])).to.be.undefined
++
++ function Clazz() {}
++ Clazz.prototype.test = []
++
++ expect(objectPath.get(new Clazz(), '__proto__')).to.be.undefined
++ expect(objectPath.get(new Clazz(), [['__proto__']])).to.be.undefined
++ expect(objectPath.get(new Clazz(), ['constructor',
'prototype'])).to.be.undefined
++ })
++
++ it('[security] should not get magic properties in inheritedProps mode',
function () {
++ expect(function() {
++ objectPath.withInheritedProps.get({}, '__proto__')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.get({}, [['__proto__']])
++ }).to.throw('For security reasons')
++
++ function Clazz() {}
++ Clazz.prototype.test = 'original'
++
++ expect(function() {
++ objectPath.withInheritedProps.get(new Clazz(), '__proto__')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.get(new Clazz(), [['__proto__']])
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.get(new Clazz(), ['constructor',
'prototype'])
++ }).to.throw('For security reasons')
++ })
+ })
+
+
+@@ -244,9 +281,15 @@
+ objectPath.set({}, [['__proto__'], 'injected'], 'this is bad')
+ expect(Object.prototype.injected).to.be.undefined
+
++ objectPath.set({}, ['__proto__'], {})
++ expect(Object.prototype.toString).to.be.a('function')
++
+ function Clazz() {}
+ Clazz.prototype.test = 'original'
+
++ objectPath.set({}, ['__proto__'], {test: 'this is bad'})
++ expect(Clazz.prototype.test).to.be.equal('original')
++
+ objectPath.set(new Clazz(), '__proto__.test', 'this is bad')
+ expect(Clazz.prototype.test).to.be.equal('original')
+
+@@ -258,9 +301,10 @@
+ })
+
+ it('[security] should throw an exception if trying to set magic properties
in inheritedProps mode', function () {
+- expect(function() {objectPath.withInheritedProps.set({},
'__proto__.injected', 'this is bad')})
+- .to.throw('For security reasons')
+- expect(Object.prototype.injected).to.be.undefined
++ expect(function() {
++ objectPath.withInheritedProps.set({}, '__proto__.injected', 'this is
bad')
++ expect(Object.prototype.injected).to.be.undefined
++ }).to.throw('For security reasons')
+
+ expect(function() {
+ objectPath.withInheritedProps.set({}, [['__proto__'], 'injected'],
'this is bad')
+@@ -270,21 +314,25 @@
+ function Clazz() {}
+ Clazz.prototype.test = 'original'
+
+- expect(function() {objectPath.withInheritedProps.set(new Clazz(),
'__proto__.test', 'this is bad')})
+- .to.throw('For security reasons')
+- expect(Clazz.prototype.test).to.be.equal('original')
++ expect(function() {
++ objectPath.withInheritedProps.set(new Clazz(), '__proto__.test', 'this
is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
+
+- expect(function() {objectPath.withInheritedProps.set(new Clazz(),
'constructor.prototype.test', 'this is bad')})
+- .to.throw('For security reasons')
+- expect(Clazz.prototype.test).to.be.equal('original')
++ expect(function() {
++ objectPath.withInheritedProps.set(new Clazz(),
'constructor.prototype.test', 'this is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
+
+- expect(function() {objectPath.withInheritedProps.set({},
'constructor.prototype.injected', 'this is OK')})
+- .to.throw('For security reasons')
+- expect(Object.prototype.injected).to.be.undefined
++ expect(function() {
++ objectPath.withInheritedProps.set({}, 'constructor.prototype.injected',
'this is OK')
++ expect(Object.prototype.injected).to.be.undefined
++ }).to.throw('For security reasons')
+
+- expect(function() {objectPath.withInheritedProps.set({},
[['constructor'], 'prototype', 'injected'], 'this is bad')})
+- .to.throw('For security reasons')
+- expect(Object.prototype.injected).to.be.undefined
++ expect(function() {
++ objectPath.withInheritedProps.set({}, [['constructor'], 'prototype',
'injected'], 'this is bad')
++ expect(Object.prototype.injected).to.be.undefined
++ }).to.throw('For security reasons')
+ })
+ })
+
+@@ -328,6 +376,39 @@
+ expect(obj).to.have.nested.property('b.e.0.0', 'l')
+ })
+
++ it('[security] should not push within prototype properties in default
mode', function () {
++ function Clazz() {}
++ Clazz.prototype.test = []
++
++ objectPath.push(new Clazz(), '__proto__.test', 'pushed')
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++
++ objectPath.push(new Clazz(), [['__proto__'], 'test'], 'pushed')
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++
++ objectPath.push(new Clazz(), 'constructor.prototype.test', 'pushed')
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ })
++
++ it('[security] should not push within prototype properties in
inheritedProps mode', function () {
++ function Clazz() {}
++ Clazz.prototype.test = []
++
++ expect(function() {
++ objectPath.withInheritedProps.push(new Clazz(), '__proto__.test',
'pushed')
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.push(new Clazz(), [['__proto__'],
'test'], 'pushed')
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.push(new Clazz(),
'constructor.prototype.test', 'pushed')
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ }).to.throw('For security reasons')
++ })
+ })
+
+
+@@ -361,6 +442,67 @@
+ expect(any[1]).to.be.an('object')
+ expect(any[1][1]).to.be.an('object')
+ })
++
++ it('[security] should not set magic properties in default mode', function
() {
++ objectPath.ensureExists({}, '__proto__.injected', 'this is bad')
++ expect(Object.prototype.injected).to.be.undefined
++
++ objectPath.ensureExists({}, [['__proto__'], 'injected'], 'this is bad')
++ expect(Object.prototype.injected).to.be.undefined
++
++ objectPath.ensureExists({}, ['__proto__'], {})
++ expect(Object.prototype.toString).to.be.a('function')
++
++ function Clazz() {}
++ Clazz.prototype.test = 'original'
++
++ objectPath.ensureExists({}, ['__proto__'], {test: 'this is bad'})
++ expect(Clazz.prototype.test).to.be.equal('original')
++
++ objectPath.ensureExists(new Clazz(), '__proto__.test', 'this is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++
++ objectPath.ensureExists(new Clazz(), [['__proto__'], 'test'], 'this is
bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++
++ objectPath.ensureExists(new Clazz(), 'constructor.prototype.test', 'this
is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ })
++
++ it('[security] should throw an exception if trying to set magic properties
in inheritedProps mode', function () {
++ expect(function() {objectPath.withInheritedProps.ensureExists({},
'__proto__.injected', 'this is bad')})
++ .to.throw('For security reasons')
++ expect(Object.prototype.injected).to.be.undefined
++
++ expect(function() {
++ objectPath.withInheritedProps.ensureExists({}, [['__proto__'],
'injected'], 'this is bad')
++ expect(Object.prototype.injected).to.be.undefined
++ }).to.throw('For security reasons')
++
++ function Clazz() {}
++ Clazz.prototype.test = 'original'
++
++ expect(function() {
++ objectPath.withInheritedProps.ensureExists(new Clazz(),
'__proto__.test', 'this is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++
++
++ expect(function() {
++ objectPath.withInheritedProps.ensureExists(new Clazz(),
'constructor.prototype.test', 'this is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.ensureExists({},
'constructor.prototype.injected', 'this is OK')
++ expect(Object.prototype.injected).to.be.undefined
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.ensureExists({}, [['constructor'],
'prototype', 'injected'], 'this is bad')
++ expect(Object.prototype.injected).to.be.undefined
++ }).to.throw('For security reasons')
++ })
+ })
+
+ describe('coalesce', function () {
+@@ -512,6 +654,40 @@
+ expect(obj.instance.arr).to.be.an('array')
+ expect(obj['function']).to.equal(null)
+ })
++
++ it('[security] should not empty prototype properties in default mode',
function () {
++ function Clazz() {}
++ Clazz.prototype.test = 'original'
++
++ objectPath.empty(new Clazz(), '__proto__')
++ expect(Clazz.prototype.test).to.be.equal('original')
++
++ objectPath.empty(new Clazz(), [['__proto__']])
++ expect(Clazz.prototype.test).to.be.equal('original')
++
++ objectPath.empty(new Clazz(), 'constructor.prototype')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ })
++
++ it('[security] should throw an exception if trying to delete prototype
properties in inheritedProps mode', function () {
++ function Clazz() {}
++ Clazz.prototype.test = 'original'
++
++ expect(function() {
++ objectPath.withInheritedProps.empty(new Clazz(), '__proto__')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.empty(new Clazz(),
'constructor.prototype')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.empty({}, [['constructor'], 'prototype'])
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++ })
+ })
+
+ describe('del', function () {
+@@ -588,6 +764,56 @@
+ expect(obj.b.d).to.have.length(0)
+ expect(obj.b.d).to.be.deep.equal([])
+ })
++
++ it('[security] should not delete prototype properties in default mode',
function () {
++ objectPath.del({}, '__proto__.valueOf')
++ expect(Object.prototype.valueOf).to.be.a('function')
++
++ objectPath.del({}, [['__proto__'], 'valueOf'])
++ expect(Object.prototype.valueOf).to.be.a('function')
++
++ function Clazz() {}
++ Clazz.prototype.test = 'original'
++
++ objectPath.del(new Clazz(), '__proto__.test')
++ expect(Clazz.prototype.test).to.be.equal('original')
++
++ objectPath.del(new Clazz(), [['__proto__'], 'test'])
++ expect(Clazz.prototype.test).to.be.equal('original')
++
++ objectPath.del(new Clazz(), 'constructor.prototype.test')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ })
++
++ it('[security] should throw an exception if trying to delete prototype
properties in inheritedProps mode', function () {
++ expect(function() {
++ objectPath.withInheritedProps.del({}, '__proto__.valueOf')
++ expect(Object.prototype.valueOf).to.be.a('function')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.del({}, [['__proto__'], 'valueOf'])
++ expect(Object.prototype.valueOf).to.be.a('function')
++ }).to.throw('For security reasons')
++
++ function Clazz() {}
++ Clazz.prototype.test = 'original'
++
++ expect(function() {
++ objectPath.withInheritedProps.del(new Clazz(), '__proto__.test')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.del(new Clazz(),
'constructor.prototype.test', 'this is bad')
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.del({}, [['constructor'], 'prototype',
'test'])
++ expect(Clazz.prototype.test).to.be.equal('original')
++ }).to.throw('For security reasons')
++ })
+ })
+
+ describe('insert', function () {
+@@ -630,6 +856,45 @@
+ 'asdf'
+ ])
+ })
++
++ it('[security] should not insert within prototype properties in default
mode', function () {
++ function Clazz() {}
++ Clazz.prototype.test = []
++
++ objectPath.insert(new Clazz(), '__proto__.test', 'inserted', 0)
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++
++ objectPath.insert(new Clazz(), [['__proto__'], 'test'], 'inserted', 0)
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++
++ objectPath.insert(new Clazz(), 'constructor.prototype.test', 'inserted',
0)
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ })
++
++ it('[security] should not insert within prototype properties in
inheritedProps mode', function () {
++ function Clazz() {}
++ Clazz.prototype.test = []
++
++ expect(function() {
++ objectPath.withInheritedProps.insert(new Clazz(), '__proto__.test',
'inserted', 0)
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.insert(new Clazz(), [['__proto__'],
'test'], 'inserted', 0)
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.insert(new Clazz(),
'constructor.prototype.test', 'inserted', 0)
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ }).to.throw('For security reasons')
++
++ expect(function() {
++ objectPath.withInheritedProps.insert(new Clazz().constructor,
'prototype.test', 'inserted', 0)
++ expect(Clazz.prototype.test).to.be.deep.equal([])
++ }).to.throw('For security reasons')
++ })
+ })
+
+ describe('has', function () {
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..7b1f359
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,2 @@
+CVE-2021-23434.patch
+CVE-2021-3805.patch
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
index 33c3a64..6fd902a 100644
--- a/debian/salsa-ci.yml
+++ b/debian/salsa-ci.yml
@@ -1,4 +1,7 @@
---
+variables:
+ RELEASE: 'bullseye'
+
include:
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
-
https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
--- End Message ---