CVE-2022-3950: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability, which was classified as problematic, was found in sanluan PublicCMS. Affected is the function initLink of the file dwz.min.js of the component Tab Handler. The manipulation leads to cross site scripting. It is possible to launch the attack remotely. The name of the patch is a972dc9b1c94aea2d84478bf26283904c21e4ca2. It is recommended to apply a patch to fix this issue. The identifier of this vulnerability is VDB-213456.
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: 2022-11-11T14:15Z
Repository: https://github.com/sanluan/PublicCMS
Language: JavaScript
Files changed: publiccms-parent/publiccms/src/main/webapp/resource/js/dwz.min.js
Commit date: 2022-09-14 17:07:50 +0800
Commit message: 标签页xss修复
Diff: diff --git a/publiccms-parent/publiccms/src/main/webapp/resource/js/dwz.min.js b/publiccms-parent/publiccms/src/main/webapp/resource/js/dwz.min.js
index dc96ff52f..fd5c01377 100644
--- a/publiccms-parent/publiccms/src/main/webapp/resource/js/dwz.min.js
+++ b/publiccms-parent/publiccms/src/main/webapp/resource/js/dwz.min.js
@@ -1940,19 +1940,15 @@ function initUI(_box) {
 function initLink($p) {
     // navTab
     $("a[target=navTab]", $p).each(function() {
         $(this).click(function(event) {
             var $this = $(this);
-            var title = $this.attr("title") || $this.text();
+             var title = $this.attr("title") || $this.text();
             if(title){
                 title = title.replace(/<[^>]*>/gi,"");
             }
-            var titleHtml = $this.attr("title") || $this.html();
-            var icon = $this.attr("icon");
-            if(icon){
-                titleHtml = icon + " " + titleHtml;
-            }
+            var icon = $this.attr("icon") || $this.find("i").prop("outerHTML");
             var tabid = $this.attr("rel") || "_blank";
             var fresh = eval($this.attr("fresh") || "true");
             var external = eval($this.attr("external") || "false");
             var url = $this.attr("href").replaceTmById($(event.target).parents(".unitBox:first"));
             var newWindow = (navigator.platform.match("Mac") ? event.metaKey : event.ctrlKey);
@@ -1960,21 +1956,21 @@ function initLink($p) {
             if (!url.isFinishedTm() ) {
                 alertMsg.error($this.attr("warn") || DWZ.msg("alertSelectMsg"));
                 return false;
             }
             navTab.openTab(tabid, url, {
-                title: title, titleHtml: titleHtml, fresh: fresh, external: external, focusNewWindow:newWindow
+                title: title, icon: icon, fresh: fresh, external: external, focusNewWindow:newWindow
             });
             return false;
         });
     });
 
     // dialogs
     $("a[target=dialog]", $p).each(function() {
         $(this).click(function(event) {
             var $this = $(this);
-            var title = $this.attr("title") || $this.html();
+            var title = $this.attr("title") || $this.text();
             var rel = $this.attr("rel") || "_blank";
             var options = {};
             var w = $this.attr("width");
             var h = $this.attr("height");
             if (w ) {
@@ -2673,11 +2669,11 @@ var navTab = {
      *            params: title, data, fresh
      */
     openTab: function(tabid, url, options) { // if found tabid replace tab,
         // else create a new tab.
         var op = $.extend({
-            title: "New Tab", titleHtml: "New Tab", data: {}, fresh: true, external: false, focusNewWindow:false
+            title: "New Tab", icon: "", data: {}, fresh: true, external: false, focusNewWindow:false
         }, options);
         var iOpenIndex = this._indexTabId(tabid);
         if (iOpenIndex >= 0 && !op.focusNewWindow) {
             var $tab = this._getTabs().eq(iOpenIndex);
             var $panel = this._getPanels().eq(iOpenIndex);
@@ -2699,12 +2695,12 @@ var navTab = {
         } else {
             if(op.focusNewWindow){
               tabid += Math.round(Math.random() * 10000000);
             }
             this._getPanels().eq(this._currentIndex).after('<div class="page unitBox"></div>');
-            this._getTabs().eq(this._currentIndex).after($('<li tabid="' + tabid + '"><a href="javascript:;" class="close"><i class="icon-remove-sign"></i></a></li>').attr('tabid',tabid).append($('<a href="javascript:"></a>').attr('title',op.title).html(op.titleHtml)));
-            this._getMoreLi().eq(this._currentIndex).after($('<li></li>').append($('<a href="javascript:"></a>').attr('title',op.title).html(op.titleHtml)));
+            this._getTabs().eq(this._currentIndex).after($('<li><a href="javascript:;" class="close"><i class="icon-remove-sign"></i></a></li>').attr('tabid',tabid).prepend($('<a href="javascript:"></a>').attr('title',op.title).text(op.title).prepend(op.icon)));
+            this._getMoreLi().eq(this._currentIndex).after($('<li></li>').append($('<a href="javascript:"></a>').attr('title',op.title).text(op.title).prepend(op.icon)));
             var $tabs = this._getTabs();
             var $tab = $tabs.eq(this._currentIndex+1);
             var $panel = this._getPanels().eq(this._currentIndex+1);
 
             if (op.external || url.isExternalUrl() ) {
@@ -2990,11 +2986,11 @@ var navTab = {
                 if (dialog.is(":hidden") ) {
                     dialog.show();
                 }
                 if (op.fresh || url != dialog.data("url") ) {
                     dialog.data("url", url);
-                    dialog.find(".dialogHeader").find("h1").html(title);
+                    dialog.find(".dialogHeader").find("h1").text(title);
                     this.switchDialog(dialog);
                     var jDContent = dialog.find(".dialogContent");
                     jDContent.loadUrl(url, {}, function() {
                         jDContent.find("[layoutH]").layoutH(jDContent);
                         $("button.close").click(function() {
@@ -3016,11 +3012,11 @@ var navTab = {
                 }
                 if (options.param ) {
                     dialog.data("param", options.param);
                 }
                 ( $.fn.bgiframe && dialog.bgiframe() );
-                dialog.find(".dialogHeader").find("h1").html(title);
+                dialog.find(".dialogHeader").find("h1").text(title);
                 dialog.css("zIndex", ( $.pdialog._zIndex += 2 ));
                 $.pdialog._init(dialog, options);
                 dialog.click(function() {
                     $.pdialog.switchDialog(dialog);
                 });

Vulnerable code:             var title = $this.attr("title") || $this.text();
            var titleHtml = $this.attr("title") || $this.html();
            var icon = $this.attr("icon");
            if(icon){
                titleHtml = icon + " " + titleHtml;
            }
                title: title, titleHtml: titleHtml, fresh: fresh, external: external, focusNewWindow:newWindow
            var title = $this.attr("title") || $this.html();
            title: "New Tab", titleHtml: "New Tab", data: {}, fresh: true, external: false, focusNewWindow:false
            this._getTabs().eq(this._currentIndex).after($('<li tabid="' + tabid + '"><a href="javascript:;" class="close"><i class="icon-remove-sign"></i></a></li>').attr('tabid',tabid).append($('<a href="javascript:"></a>').attr('title',op.title).html(op.titleHtml)));
            this._getMoreLi().eq(this._currentIndex).after($('<li></li>').append($('<a href="javascript:"></a>').attr('title',op.title).html(op.titleHtml)));
                    dialog.find(".dialogHeader").find("h1").html(title);
                dialog.find(".dialogHeader").find("h1").html(title);
Fixed code:              var title = $this.attr("title") || $this.text();
            var icon = $this.attr("icon") || $this.find("i").prop("outerHTML");
                title: title, icon: icon, fresh: fresh, external: external, focusNewWindow:newWindow
            var title = $this.attr("title") || $this.text();
            title: "New Tab", icon: "", data: {}, fresh: true, external: false, focusNewWindow:false
            this._getTabs().eq(this._currentIndex).after($('<li><a href="javascript:;" class="close"><i class="icon-remove-sign"></i></a></li>').attr('tabid',tabid).prepend($('<a href="javascript:"></a>').attr('title',op.title).text(op.title).prepend(op.icon)));
            this._getMoreLi().eq(this._currentIndex).after($('<li></li>').append($('<a href="javascript:"></a>').attr('title',op.title).text(op.title).prepend(op.icon)));
                    dialog.find(".dialogHeader").find("h1").text(title);
                dialog.find(".dialogHeader").find("h1").text(title);