CVE-2023-25314: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross Site Scripting (XSS) vulnerability in World Wide Broadcast Network AVideo before 12.4, allows attackers to gain sensitive information via the success parameter to /user.
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-04-25T16:15Z
Repository: https://github.com/WWBN/AVideo
Language: JavaScript
Files changed: view/js/script.js
Commit date: 2023-01-31 11:59:34 -0300
Commit message: Thanks Jefferson Gonzales

this update prevents the XSS attack

Description:

While making an account in demo.avideo.com I found a parameter "?success=" which did not sanitize any symbol character properly which leads to XSS attack.

Impact:

Since there's an Admin account on demo.avideo.com attacker can use this attack to Takeover the admin's account

Step to Reproduce:

1. Click the link below

https://demo.avideo.com/user?success="><img src=x onerror=alert(document.cookie)>

2. Then XSS will be executed
Diff: diff --git a/view/js/script.js b/view/js/script.js
index 65e4da6d93..95b04ded05 100644
--- a/view/js/script.js
+++ b/view/js/script.js
@@ -2963,15 +2963,100 @@ $(document).ready(function () {
     _alertFromGet('success');
     _alertFromGet('toast');
 
 });
 
+/*!
+ * Sanitize an HTML string
+ * (c) 2021 Chris Ferdinandi, MIT License, https://gomakethings.com
+ * @param  {String}          str   The HTML string to sanitize
+ * @param  {Boolean}         nodes If true, returns HTML nodes instead of a string
+ * @return {String|NodeList}       The sanitized string or nodes
+ */
+function cleanHTML (str, nodes) {
+
+	/**
+	 * Convert the string to an HTML document
+	 * @return {Node} An HTML document
+	 */
+	function stringToHTML () {
+		let parser = new DOMParser();
+		let doc = parser.parseFromString(str, 'text/html');
+		return doc.body || document.createElement('body');
+	}
+
+	/**
+	 * Remove <script> elements
+	 * @param  {Node} html The HTML
+	 */
+	function removeScripts (html) {
+		let scripts = html.querySelectorAll('script');
+		for (let script of scripts) {
+			script.remove();
+		}
+	}
+
+	/**
+	 * Check if the attribute is potentially dangerous
+	 * @param  {String}  name  The attribute name
+	 * @param  {String}  value The attribute value
+	 * @return {Boolean}       If true, the attribute is potentially dangerous
+	 */
+	function isPossiblyDangerous (name, value) {
+		let val = value.replace(/\s+/g, '').toLowerCase();
+		if (['src', 'href', 'xlink:href'].includes(name)) {
+			if (val.includes('javascript:') || val.includes('data:text/html')) return true;
+		}
+		if (name.startsWith('on')) return true;
+	}
+
+	/**
+	 * Remove potentially dangerous attributes from an element
+	 * @param  {Node} elem The element
+	 */
+	function removeAttributes (elem) {
+
+		// Loop through each attribute
+		// If it's dangerous, remove it
+		let atts = elem.attributes;
+		for (let {name, value} of atts) {
+			if (!isPossiblyDangerous(name, value)) continue;
+			elem.removeAttribute(name);
+		}
+
+	}
+
+	/**
+	 * Remove dangerous stuff from the HTML document's nodes
+	 * @param  {Node} html The HTML document
+	 */
+	function clean (html) {
+		let nodes = html.children;
+		for (let node of nodes) {
+			removeAttributes(node);
+			clean(node);
+		}
+	}
+
+	// Convert the string to HTML
+	let html = stringToHTML();
+
+	// Sanitize it
+	removeScripts(html);
+	clean(html);
+
+	// If the user wants HTML nodes back, return them
+	// Otherwise, pass a sanitized string back
+	return nodes ? html.childNodes : html.innerHTML;
+
+}
+
 async function _alertFromGet(type) {
     if (urlParams.has(type)) {
         var msg = urlParams.get(type);
         var div = document.createElement("div");
-        div.innerHTML = msg;
+        div.innerHTML = cleanHTML(msg, false);
         var text = div.textContent || div.innerText || "";
         if (!empty(text)) {
             switch (type) {
                 case 'error':
                     avideoAlertError(text);

Vulnerable code:         div.innerHTML = msg;
Fixed code: /*!
 * Sanitize an HTML string
 * (c) 2021 Chris Ferdinandi, MIT License, https://gomakethings.com
 * @param  {String}          str   The HTML string to sanitize
 * @param  {Boolean}         nodes If true, returns HTML nodes instead of a string
 * @return {String|NodeList}       The sanitized string or nodes
 */
function cleanHTML (str, nodes) {

	/**
	 * Convert the string to an HTML document
	 * @return {Node} An HTML document
	 */
	function stringToHTML () {
		let parser = new DOMParser();
		let doc = parser.parseFromString(str, 'text/html');
		return doc.body || document.createElement('body');
	}

	/**
	 * Remove <script> elements
	 * @param  {Node} html The HTML
	 */
	function removeScripts (html) {
		let scripts = html.querySelectorAll('script');
		for (let script of scripts) {
			script.remove();
		}
	}

	/**
	 * Check if the attribute is potentially dangerous
	 * @param  {String}  name  The attribute name
	 * @param  {String}  value The attribute value
	 * @return {Boolean}       If true, the attribute is potentially dangerous
	 */
	function isPossiblyDangerous (name, value) {
		let val = value.replace(/\s+/g, '').toLowerCase();
		if (['src', 'href', 'xlink:href'].includes(name)) {
			if (val.includes('javascript:') || val.includes('data:text/html')) return true;
		}
		if (name.startsWith('on')) return true;
	}

	/**
	 * Remove potentially dangerous attributes from an element
	 * @param  {Node} elem The element
	 */
	function removeAttributes (elem) {

		// Loop through each attribute
		// If it's dangerous, remove it
		let atts = elem.attributes;
		for (let {name, value} of atts) {
			if (!isPossiblyDangerous(name, value)) continue;
			elem.removeAttribute(name);
		}

	}

	/**
	 * Remove dangerous stuff from the HTML document's nodes
	 * @param  {Node} html The HTML document
	 */
	function clean (html) {
		let nodes = html.children;
		for (let node of nodes) {
			removeAttributes(node);
			clean(node);
		}
	}

	// Convert the string to HTML
	let html = stringToHTML();

	// Sanitize it
	removeScripts(html);
	clean(html);

	// If the user wants HTML nodes back, return them
	// Otherwise, pass a sanitized string back
	return nodes ? html.childNodes : html.innerHTML;

}

        div.innerHTML = cleanHTML(msg, false);