CVE-2021-23390 (JavaScript, published 2021-07-12T16:15Z)
Description: value: The package total4 before 0.0.43 are vulnerable to Arbitrary Code Execution via the U.set() and U.get() functions.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-94 \u2014 Improper Control of Generation of Code ('Code Injection')
The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
Repository: https://github.com/totaljs/framework4
Files changed:
changelog.txt
utils.js
Commit message: Removed useless methods.


Vulnerable code:
exports.sync = function(fn, owner) {
	return function() {

		var args = [].slice.call(arguments);
		var params;
		var callback;
		var executed = false;
		var self = owner || this;

		args.push(function() {
			params = arguments;
			if (!executed && callback) {
				executed = true;
				callback.apply(self, params);
			}
		});

		fn.apply(self, args);

		return function(cb) {
			callback = cb;
			if (!executed && params) {
				executed = true;
				callback.apply(self, params);
			}
		};
	};
};

exports.sync2 = function(fn, owner) {
	return (function() {

		var params;
		var callback;
		var executed = false;
		var self = owner || this;
		var args = [].slice.call(arguments);

		args.push(function() {
			params = arguments;
			if (!executed && callback) {
				executed = true;
				callback.apply(self, params);
			}
		});

		fn.apply(self, args);

		return function(cb) {
			callback = cb;
			if (!executed && params) {
				executed = true;
				callback.apply(self, params);
			}
		};
	})();
};

exports.set = function(obj, path, value) {
	var cachekey = 'S+' + path;

	if (F.temporary.other[cachekey])
		return F.temporary.other[cachekey](obj, value);

	var arr = parsepath(path);
	var builder = [];

	for (var i = 0; i < arr.length - 1; i++) {
		var type = arr[i + 1] ? (REGISARR.test(arr[i + 1]) ? '[]' : '{}') : '{}';
		var p = 'w' + (arr[i][0] === '[' ? '' : '.') + arr[i];
		builder.push('if(typeof(' + p + ')!==\'object\'||' + p + '==null)' + p + '=' + type + ';');
	}

	var v = arr[arr.length - 1];
	var ispush = v.lastIndexOf('[]') !== -1;
	var a = builder.join(';') + ';var v=typeof(a)===\'function\'?a(U.get(b)):a;w' + (v[0] === '[' ? '' : '.') + (ispush ? v.replace(REGREPLACEARR, '.push(v)') : (v + '=v')) + ';return v';

	if ((/__proto__|constructor|prototype|eval/).test(a))
		throw new Error('Potential vulnerability');

	var fn = new Function('w', 'a', 'b', a);
	F.temporary.other[cachekey] = fn;
	fn(obj, value, path);
};

exports.get = function(obj, path) {

	var cachekey = 'G=' + path;

	if (F.temporary.other[cachekey])
		return F.temporary.other[cachekey](obj);

	var arr = parsepath(path);
	var builder = [];

	for (var i = 0, length = arr.length - 1; i < length; i++)
		builder.push('if(!w' + (!arr[i] || arr[i][0] === '[' ? '' : '.') + arr[i] + ')return');

	var v = arr[arr.length - 1];
	var fn = (new Function('w', builder.join(';') + ';return w' + (v[0] === '[' ? '' : '.') + v));
	F.temporary.other[cachekey] = fn;
	return fn(obj);
};

function parsepath(path) {

	var arr = path.split('.');
	var builder = [];
	var all = [];

	for (var i = 0; i < arr.length; i++) {
		var p = arr[i];
		var index = p.indexOf('[');
		if (index === -1) {
			if (p.indexOf('-') === -1) {
				all.push(p);
				builder.push(all.join('.'));
			} else {
				var a = all.splice(all.length - 1);
				all.push(a + '[\'' + p + '\']');
				builder.push(all.join('.'));
			}
		} else {
			if (p.indexOf('-') === -1) {
				all.push(p.substring(0, index));
				builder.push(all.join('.'));
				all.splice(all.length - 1);
				all.push(p);
				builder.push(all.join('.'));
			} else {
				all.push('[\'' + p.substring(0, index) + '\']');
				builder.push(all.join(''));
				all.push(p.substring(index));
				builder.push(all.join(''));
			}
		}
	}

	return builder;
}

global.sync = exports.sync;
global.sync2 = exports.sync2;


Fixed code:
- removed method `U.set()`
- removed method `U.get()`
- removed method `U.sync()` and `global.sync()`
- removed method `U.sync2()` and `global.sync2()`