CVE-2022-25979: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Versions of the package jsuites before 5.0.1 are vulnerable to Cross-site Scripting (XSS) due to improper user-input sanitization in the Editor() function.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2023-01-31T05:15Z
Repository: https://github.com/jsuites/jsuites
Language: JavaScript
Files changed: dist/jsuites.js, src/jsuites.js, src/plugins/editor.js
Commit date: 2023-01-13 21:43:16 +0000
Commit message: jSuites 5 editor - security fixes.

Diff: diff --git a/dist/jsuites.js b/dist/jsuites.js
index dfa8731..09e3d78 100644
--- a/dist/jsuites.js
+++ b/dist/jsuites.js
@@ -304,11 +304,11 @@ return /******/ (function() { // webpackBootstrap
 
 /******/ 	});
 /************************************************************************/
 /******/ 	// The module cache
 /******/ 	var __webpack_module_cache__ = {};
-/******/
+/******/ 	
 /******/ 	// The require function
 /******/ 	function __webpack_require__(moduleId) {
 /******/ 		// Check if module is in cache
 /******/ 		var cachedModule = __webpack_module_cache__[moduleId];
 /******/ 		if (cachedModule !== undefined) {
@@ -318,18 +318,18 @@ return /******/ (function() { // webpackBootstrap
 /******/ 		var module = __webpack_module_cache__[moduleId] = {
 /******/ 			// no module.id needed
 /******/ 			// no module.loaded needed
 /******/ 			exports: {}
 /******/ 		};
-/******/
+/******/ 	
 /******/ 		// Execute the module function
 /******/ 		__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-/******/
+/******/ 	
 /******/ 		// Return the exports of the module
 /******/ 		return module.exports;
 /******/ 	}
-/******/
+/******/ 	
 /************************************************************************/
 /******/ 	/* webpack/runtime/compat get default export */
 /******/ 	!function() {
 /******/ 		// getDefaultExport function for compatibility with non-harmony modules
 /******/ 		__webpack_require__.n = function(module) {
@@ -338,11 +338,11 @@ return /******/ (function() { // webpackBootstrap
 /******/ 				function() { return module; };
 /******/ 			__webpack_require__.d(getter, { a: getter });
 /******/ 			return getter;
 /******/ 		};
 /******/ 	}();
-/******/
+/******/ 	
 /******/ 	/* webpack/runtime/define property getters */
 /******/ 	!function() {
 /******/ 		// define getter functions for harmony exports
 /******/ 		__webpack_require__.d = function(exports, definition) {
 /******/ 			for(var key in definition) {
@@ -350,16 +350,16 @@ return /******/ (function() { // webpackBootstrap
 /******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
 /******/ 				}
 /******/ 			}
 /******/ 		};
 /******/ 	}();
-/******/
+/******/ 	
 /******/ 	/* webpack/runtime/hasOwnProperty shorthand */
 /******/ 	!function() {
 /******/ 		__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
 /******/ 	}();
-/******/
+/******/ 	
 /************************************************************************/
 var __webpack_exports__ = {};
 // This entry need to be wrapped in an IIFE because it need to be in strict mode.
 !function() {
 "use strict";
@@ -1245,32 +1245,32 @@ function Ajax() {
 ;// CONCATENATED MODULE: ./src/plugins/animation.js
 function Animation() {
     var Component = {
         loading: {}
     }
-
+    
     Component.loading.show = function(timeout) {
         if (! Component.loading.element) {
             Component.loading.element = document.createElement('div');
             Component.loading.element.className = 'jloading';
         }
         document.body.appendChild(Component.loading.element);
-
+    
         // Max timeout in seconds
         if (timeout > 0) {
             setTimeout(function() {
                 obj.hide();
             }, timeout * 1000)
         }
     }
-
+    
     Component.loading.hide = function() {
         if (Component.loading.element && Component.loading.element.parentNode) {
             document.body.removeChild(Component.loading.element);
         }
     }
-
+    
     Component.slideLeft = function (element, direction, done) {
         if (direction == true) {
             element.classList.add('slide-left-in');
             setTimeout(function () {
                 element.classList.remove('slide-left-in');
@@ -1286,11 +1286,11 @@ function Animation() {
                     done();
                 }
             }, 400);
         }
     }
-
+    
     Component.slideRight = function (element, direction, done) {
         if (direction == true) {
             element.classList.add('slide-right-in');
             setTimeout(function () {
                 element.classList.remove('slide-right-in');
@@ -1306,11 +1306,11 @@ function Animation() {
                     done();
                 }
             }, 400);
         }
     }
-
+    
     Component.slideTop = function (element, direction, done) {
         if (direction == true) {
             element.classList.add('slide-top-in');
             setTimeout(function () {
                 element.classList.remove('slide-top-in');
@@ -1326,11 +1326,11 @@ function Animation() {
                     done();
                 }
             }, 400);
         }
     }
-
+    
     Component.slideBottom = function (element, direction, done) {
         if (direction == true) {
             element.classList.add('slide-bottom-in');
             setTimeout(function () {
                 element.classList.remove('slide-bottom-in');
@@ -1346,22 +1346,22 @@ function Animation() {
                     done();
                 }
             }, 100);
         }
     }
-
+    
     Component.fadeIn = function (element, done) {
         element.style.display = '';
         element.classList.add('fade-in');
         setTimeout(function () {
             element.classList.remove('fade-in');
             if (typeof (done) == 'function') {
                 done();
             }
         }, 2000);
     }
-
+    
     Component.fadeOut = function (element, done) {
         element.classList.add('fade-out');
         setTimeout(function () {
             element.style.display = 'none';
             element.classList.remove('fade-out');
@@ -7944,11 +7944,11 @@ function Toolbar(el, options) {
         for (var i = 0; i < items.length; i++) {
             var toolbarItem = document.createElement('div');
             toolbarItem.classList.add('jtoolbar-item');
 
             if (items[i].width) {
-                toolbarItem.style.width = parseInt(items[i].width) + 'px';
+                toolbarItem.style.width = parseInt(items[i].width) + 'px'; 
             }
 
             if (items[i].k) {
                 toolbarItem.k = items[i].k;
             }
@@ -8190,11 +8190,12 @@ function Editor() {
             onblur: null,
             onload: null,
             onkeyup: null,
             onkeydown: null,
             onchange: null,
-            extensions: null
+            extensions: null,
+            type: null,
         };
 
         // Loop through our object
         for (var property in defaults) {
             if (options && options.hasOwnProperty(property)) {
@@ -8714,24 +8715,28 @@ function Editor() {
                    if (! obj.options.acceptImages || ! element.src) {
                        element.parentNode.removeChild(element);
                    } else {
                        // Check if is data
                        element.setAttribute('tabindex', '900');
-                       // Check attributes for persistance
+                       // Check attributes for persistence
                        obj.addImage(element.src);
                    }
                }
                // Remove attributes
                var attr = [];
-               var numAttributes = element.attributes.length - 1;
-               if (numAttributes > 0) {
-                   for (var i = numAttributes; i >= 0 ; i--) {
-                       attr.push(element.attributes[i].name);
-                   }
+               for (var i = 0; i < element.attributes.length; i++) {
+                   attr.push(element.attributes[i].name);
+               }
+               if (attr.length) {
                    attr.forEach(function(v) {
                        if (validProperty.indexOf(v) == -1) {
                            element.removeAttribute(v);
+                       } else {
+                           // Protection XSS
+                           if (element.attributes[i].value.indexOf('<') !== -1) {
+                               element.attributes[i].value.replace('<', '&#60;');
+                           }
                        }
                    });
                }
                element.style = '';
                // Add valid style
@@ -9397,23 +9402,22 @@ function Editor() {
             });
 
             items.push({
                 type: 'select',
                 content: 'table_view',
-                columns: 10,
+                columns: 8,
+                grid: 8,
                 right: true,
                 options: [
-                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0', '8x0', '9x0',
-                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1', '8x1', '9x1',
-                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2', '8x2', '9x2',
-                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3', '8x3', '9x3',
-                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4', '8x4', '9x4',
-                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5', '8x5', '9x5',
-                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6', '8x6', '9x6',
-                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7', '8x7', '9x7',
-                    '0x8', '1x8', '2x8', '3x8', '4x8', '5x8', '6x8', '7x8', '8x8', '9x8',
-                    '0x9', '1x9', '2x9', '3x9', '4x9', '5x9', '6x9', '7x9', '8x9', '9x9',
+                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0',
+                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1',
+                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2',
+                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3',
+                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4',
+                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5',
+                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6',
+                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7',
                 ],
                 render: function (e, item) {
                     if (item) {
                         item.onmouseover = this.onmouseover;
                         e = e.split('x');
@@ -9722,21 +9726,21 @@ function Validations() {
 
             return component[options.type](value, options);
         }
         return null;
     }
-
+    
     component.url = function() {
         var pattern = new RegExp(/(((https?:\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]+)/ig);
         return pattern.test(data) ? true : false;
     }
 
     component.email = function(data) {
         var pattern = new RegExp(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
-        return data && pattern.test(data) ? true : false;
+        return data && pattern.test(data) ? true : false; 
     }
-
+    
     component.required = function(data) {
         return data.trim() ? true : false;
     }
 
     component.exist = function(data, options) {
@@ -11284,11 +11288,11 @@ function Slider(el, options) {
         // Move children inside
         if (el.children.length > 0) {
             // Keep children items
             for (var i = 0; i < el.children.length; i++) {
                 obj.options.items.push(el.children[i]);
-
+                
                 // counter click event
                 var item = document.createElement('div');
                 item.onclick = function() {
                     var index = Array.prototype.slice.call(counter.children).indexOf(this);
                     obj.show(obj.currentImage = obj.options.items[index]);
@@ -11303,11 +11307,11 @@ function Slider(el, options) {
         // Add close buttom
         var controls = document.createElement('div');
         var close = document.createElement('div');
         close.className = 'jslider-close';
         close.innerHTML = '';
-
+        
         close.onclick = function() {
             obj.close();
         }
         controls.appendChild(caption);
         controls.appendChild(close);
@@ -11409,11 +11413,11 @@ function Slider(el, options) {
         var nextImage = obj.currentImage.nextElementSibling;
         if (nextImage && nextImage.tagName === 'IMG') {
             obj.show(obj.currentImage.nextElementSibling);
         }
     }
-
+    
     obj.prev = function() {
         if (obj.currentImage.previousElementSibling) {
             obj.show(obj.currentImage.previousElementSibling);
         }
     }
@@ -11573,11 +11577,11 @@ function Tags(el, options) {
     obj.add = function(value, focus) {
         if (typeof(obj.options.onbeforechange) == 'function') {
             var ret = obj.options.onbeforechange(el, obj, obj.options.value, value);
             if (ret === false) {
                 return false;
-            } else {
+            } else { 
                 if (ret != null) {
                     value = ret;
                 }
             }
         }
@@ -11762,11 +11766,11 @@ function Tags(el, options) {
     }
 
     /**
      * Add one element from the suggestions to the element
      * @param {object} item - Node element in the suggestions container
-     */
+     */ 
     obj.selectIndex = function(text, value) {
         var node = helpers.getNode();
         if (node) {
             // Append text to the caret
             node.innerText = text;
@@ -12500,11 +12504,11 @@ var sha512_default = /*#__PURE__*/__webpack_require__.n(sha512);
 
 
 
 var jSuites = {
     /** Current version */
-    version: '5.0.0',
+    version: '5.0.1',
     /** Bind new extensions to Jsuites */
     setExtensions: function(o) {
         if (typeof(o) == 'object') {
             var k = Object.keys(o);
             for (var i = 0; i < k.length; i++) {
diff --git a/src/jsuites.js b/src/jsuites.js
index f45080e..ff574c0 100644
--- a/src/jsuites.js
+++ b/src/jsuites.js
@@ -50,11 +50,11 @@ import './style/tabs.css';
 import './style/tags.css';
 import './style/toolbar.css';
 
 var jSuites = {
     /** Current version */
-    version: '5.0.0',
+    version: '5.0.1',
     /** Bind new extensions to Jsuites */
     setExtensions: function(o) {
         if (typeof(o) == 'object') {
             var k = Object.keys(o);
             for (var i = 0; i < k.length; i++) {
diff --git a/src/plugins/editor.js b/src/plugins/editor.js
index 64d6ad5..2dddc6f 100644
--- a/src/plugins/editor.js
+++ b/src/plugins/editor.js
@@ -43,11 +43,12 @@ function Editor() {
             onblur: null,
             onload: null,
             onkeyup: null,
             onkeydown: null,
             onchange: null,
-            extensions: null
+            extensions: null,
+            type: null,
         };
 
         // Loop through our object
         for (var property in defaults) {
             if (options && options.hasOwnProperty(property)) {
@@ -567,24 +568,28 @@ function Editor() {
                    if (! obj.options.acceptImages || ! element.src) {
                        element.parentNode.removeChild(element);
                    } else {
                        // Check if is data
                        element.setAttribute('tabindex', '900');
-                       // Check attributes for persistance
+                       // Check attributes for persistence
                        obj.addImage(element.src);
                    }
                }
                // Remove attributes
                var attr = [];
-               var numAttributes = element.attributes.length - 1;
-               if (numAttributes > 0) {
-                   for (var i = numAttributes; i >= 0 ; i--) {
-                       attr.push(element.attributes[i].name);
-                   }
+               for (var i = 0; i < element.attributes.length; i++) {
+                   attr.push(element.attributes[i].name);
+               }
+               if (attr.length) {
                    attr.forEach(function(v) {
                        if (validProperty.indexOf(v) == -1) {
                            element.removeAttribute(v);
+                       } else {
+                           // Protection XSS
+                           if (element.attributes[i].value.indexOf('<') !== -1) {
+                               element.attributes[i].value.replace('<', '&#60;');
+                           }
                        }
                    });
                }
                element.style = '';
                // Add valid style
@@ -1250,23 +1255,22 @@ function Editor() {
             });
 
             items.push({
                 type: 'select',
                 content: 'table_view',
-                columns: 10,
+                columns: 8,
+                grid: 8,
                 right: true,
                 options: [
-                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0', '8x0', '9x0',
-                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1', '8x1', '9x1',
-                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2', '8x2', '9x2',
-                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3', '8x3', '9x3',
-                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4', '8x4', '9x4',
-                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5', '8x5', '9x5',
-                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6', '8x6', '9x6',
-                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7', '8x7', '9x7',
-                    '0x8', '1x8', '2x8', '3x8', '4x8', '5x8', '6x8', '7x8', '8x8', '9x8',
-                    '0x9', '1x9', '2x9', '3x9', '4x9', '5x9', '6x9', '7x9', '8x9', '9x9',
+                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0',
+                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1',
+                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2',
+                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3',
+                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4',
+                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5',
+                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6',
+                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7',
                 ],
                 render: function (e, item) {
                     if (item) {
                         item.onmouseover = this.onmouseover;
                         e = e.split('x');

Vulnerable code: /******/
/******/
/******/
/******/
/******/
/******/
/******/









                toolbarItem.style.width = parseInt(items[i].width) + 'px';
            extensions: null
                       // Check attributes for persistance
               var numAttributes = element.attributes.length - 1;
               if (numAttributes > 0) {
                   for (var i = numAttributes; i >= 0 ; i--) {
                       attr.push(element.attributes[i].name);
                   }
                columns: 10,
                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0', '8x0', '9x0',
                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1', '8x1', '9x1',
                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2', '8x2', '9x2',
                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3', '8x3', '9x3',
                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4', '8x4', '9x4',
                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5', '8x5', '9x5',
                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6', '8x6', '9x6',
                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7', '8x7', '9x7',
                    '0x8', '1x8', '2x8', '3x8', '4x8', '5x8', '6x8', '7x8', '8x8', '9x8',
                    '0x9', '1x9', '2x9', '3x9', '4x9', '5x9', '6x9', '7x9', '8x9', '9x9',

        return data && pattern.test(data) ? true : false;




            } else {
     */
    version: '5.0.0',
    version: '5.0.0',
            extensions: null
                       // Check attributes for persistance
               var numAttributes = element.attributes.length - 1;
               if (numAttributes > 0) {
                   for (var i = numAttributes; i >= 0 ; i--) {
                       attr.push(element.attributes[i].name);
                   }
                columns: 10,
                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0', '8x0', '9x0',
                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1', '8x1', '9x1',
                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2', '8x2', '9x2',
                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3', '8x3', '9x3',
                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4', '8x4', '9x4',
                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5', '8x5', '9x5',
                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6', '8x6', '9x6',
                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7', '8x7', '9x7',
                    '0x8', '1x8', '2x8', '3x8', '4x8', '5x8', '6x8', '7x8', '8x8', '9x8',
                    '0x9', '1x9', '2x9', '3x9', '4x9', '5x9', '6x9', '7x9', '8x9', '9x9',
Fixed code: /******/ 	
/******/ 	
/******/ 	
/******/ 	
/******/ 	
/******/ 	
/******/ 	
    
    
    
    
    
    
    
    
    
                toolbarItem.style.width = parseInt(items[i].width) + 'px'; 
            extensions: null,
            type: null,
                       // Check attributes for persistence
               for (var i = 0; i < element.attributes.length; i++) {
                   attr.push(element.attributes[i].name);
               }
               if (attr.length) {
                       } else {
                           // Protection XSS
                           if (element.attributes[i].value.indexOf('<') !== -1) {
                               element.attributes[i].value.replace('<', '&#60;');
                           }
                columns: 8,
                grid: 8,
                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0',
                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1',
                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2',
                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3',
                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4',
                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5',
                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6',
                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7',
    
        return data && pattern.test(data) ? true : false; 
    
                
        
    
            } else { 
     */ 
    version: '5.0.1',
    version: '5.0.1',
            extensions: null,
            type: null,
                       // Check attributes for persistence
               for (var i = 0; i < element.attributes.length; i++) {
                   attr.push(element.attributes[i].name);
               }
               if (attr.length) {
                       } else {
                           // Protection XSS
                           if (element.attributes[i].value.indexOf('<') !== -1) {
                               element.attributes[i].value.replace('<', '&#60;');
                           }
                columns: 8,
                grid: 8,
                    '0x0', '1x0', '2x0', '3x0', '4x0', '5x0', '6x0', '7x0',
                    '0x1', '1x1', '2x1', '3x1', '4x1', '5x1', '6x1', '7x1',
                    '0x2', '1x2', '2x2', '3x2', '4x2', '5x2', '6x2', '7x2',
                    '0x3', '1x3', '2x3', '3x3', '4x3', '5x3', '6x3', '7x3',
                    '0x4', '1x4', '2x4', '3x4', '4x4', '5x4', '6x4', '7x4',
                    '0x5', '1x5', '2x5', '3x5', '4x5', '5x5', '6x5', '7x5',
                    '0x6', '1x6', '2x6', '3x6', '4x6', '5x6', '6x6', '7x6',
                    '0x7', '1x7', '2x7', '3x7', '4x7', '5x7', '6x7', '7x7',