CVE-2014-9905: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Multiple cross-site scripting (XSS) vulnerabilities in the Web Calendar in SOGo before 2.2.0 allow remote attackers to inject arbitrary web script or HTML via the (1) title of an appointment or (2) contact fields.
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: 2017-02-17T17:59Z
Repository: https://github.com/inverse-inc/sogo
Language: JavaScript
Files changed: UI/WebServerResources/SchedulerUI.js, UI/WebServerResources/generic.js
Commit date: 2014-02-07 16:12:14 -0500
Commit message: Escape HTML in CSS dialogs

Diff: diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js
index 2d5557125..c7773c337 100644
--- a/UI/WebServerResources/SchedulerUI.js
+++ b/UI/WebServerResources/SchedulerUI.js
@@ -263,11 +263,11 @@ function deleteEvent() {
                             }
                             else {
                                 content = nodes[i].allTextContent();
                             }
                             itemElement.appendChild(colorBox);
-                            itemElement.appendChild(new Element('span').update(content));
+                            itemElement.appendChild(new Element('span').update(content.escapeHTML()));
                             if (nodes[i].startDate) {
                                 var startDate = new Date(nodes[i].startDate*1000);
                                 var dateElement = new Element('div', {'class': 'muted'});
                                 var date;
                                 if (typeof nodes[i].hour == 'undefined')
@@ -330,11 +330,11 @@ function deleteEvent() {
                             if (node.nodeType == Node.TEXT_NODE) {
                                 content += node.nodeValue;
                             }
                         }
                         itemElement.appendChild(colorBox);
-                        itemElement.appendChild(new Element('span').update(content));
+                        itemElement.appendChild(new Element('span').update(content.escapeHTML()));
                         if (selectedCalendarCell[i].startDate) {
                             var startDate = new Date(selectedCalendarCell[i].startDate*1000);
                             var dateElement = new Element('div', {'class': 'muted'});
                             var date;
                             if (selectedCalendarCell[i].readAttribute('hour') == 'allday')
diff --git a/UI/WebServerResources/generic.js b/UI/WebServerResources/generic.js
index ced3c99b0..e5b669314 100644
--- a/UI/WebServerResources/generic.js
+++ b/UI/WebServerResources/generic.js
@@ -1465,11 +1465,11 @@ function showAlarmCallback(http) {
             if (data["location"].length)
                 msg += "\n" + _("Location:") + " " + data["location"];
             if (data["description"].length)
                 msg += "\n\n" + data["description"];
 
-            window.alert(msg);
+            window.alert(msg.unescapeHTML());
             showSelectDialog(data["summary"], _('Snooze for '),
                              { '5': _('5 minutes'),
                                '10': _('10 minutes'),
                                '15': _('15 minutes'),
                                '30': _('30 minutes'),
@@ -1981,11 +1981,11 @@ function createDialog(id, title, legend, content, positionClass) {
     }
 
     var subdiv = createElement("div", null, null, null, null, newDialog);
     if (title && title.length > 0) {
         var titleh3 = createElement("h3", null, null, null, null, subdiv);
-        titleh3.appendChild(document.createTextNode(title));
+        titleh3.update(title);
     }
     if (legend) {
         if (Object.isElement(legend))
             subdiv.appendChild(legend);
         else if (legend.length > 0) {
@@ -2139,18 +2139,18 @@ function _showSelectDialog(title, label, options, button, callbackFcn, callbackA
     if (dialog) {
         $("bgDialogDiv").show();
     }
     else {
         var fields = createElement("p", null, []);
-	fields.appendChild(document.createTextNode(label));
+	fields.update(label);
         var select = createElement("select"); //, null, null, { cname: name } );
 	fields.appendChild(select);
         var values = $H(options).keys();
         for (var i = 0; i < values.length; i++) {
             var option = createElement("option", null, null,
                                        { value: values[i] }, null, select);
-            option.appendChild(document.createTextNode(options[values[i]]));
+            option.update(options[values[i]]);
         }
         fields.appendChild(createElement("br"));
 
         fields.appendChild(createButton(null,
                                         button,

Vulnerable code:                             itemElement.appendChild(new Element('span').update(content));
                        itemElement.appendChild(new Element('span').update(content));
            window.alert(msg);
        titleh3.appendChild(document.createTextNode(title));
	fields.appendChild(document.createTextNode(label));
            option.appendChild(document.createTextNode(options[values[i]]));
Fixed code:                             itemElement.appendChild(new Element('span').update(content.escapeHTML()));
                        itemElement.appendChild(new Element('span').update(content.escapeHTML()));
            window.alert(msg.unescapeHTML());
        titleh3.update(title);
	fields.update(label);
            option.update(options[values[i]]);