CVE-2016-6191: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Multiple cross-site scripting (XSS) vulnerabilities in the View Raw Source page in the Web Calendar in SOGo before 3.1.3 allow remote attackers to inject arbitrary web script or HTML via the (1) Description, (2) Location, (3) URL, or (4) Title field.
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: Other
Files changed: NEWS, UI/Scheduler/UIxComponentEditor.m, UI/WebServerResources/js/Scheduler/ComponentController.js
Commit date: 2016-06-08 16:06:58 -0400
Commit message: Escape HTML in raw source of events and tasks

Fixes #3718

Diff: diff --git a/NEWS b/NEWS
index fa0b73f9db..029c86ece1 100644
--- a/NEWS
+++ b/NEWS
@@ -2,10 +2,11 @@
 ------------------
 
 Bug fixes
  - [web] fixed generic avatar in lists (#3719)
  - [web] fixed validation in Sieve filter editor
+ - [web] properly encode events and tasks rawsource to avoid XSS issues (#3718)
 
 3.1.2 (2016-06-06)
 ------------------
 
 Enhancements
diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m
index 4f6072ac83..b0f901a3d6 100644
--- a/UI/Scheduler/UIxComponentEditor.m
+++ b/UI/Scheduler/UIxComponentEditor.m
@@ -873,11 +873,11 @@ - (WOResponse *) rawAction
   response = [context response];
 
   [content appendFormat: @"%@", [[self clientObject] contentAsString]];
   [response setHeader: @"text/plain; charset=utf-8" 
             forKey: @"content-type"];
-  [response appendContentString: content];
+  [response appendContentString: [content stringByEscapingHTMLString]];
 
   return response;
 }
 
 + (NSArray *) reminderValues
diff --git a/UI/WebServerResources/js/Scheduler/ComponentController.js b/UI/WebServerResources/js/Scheduler/ComponentController.js
index 6f28c18d85..81be3c7fd7 100644
--- a/UI/WebServerResources/js/Scheduler/ComponentController.js
+++ b/UI/WebServerResources/js/Scheduler/ComponentController.js
@@ -165,27 +165,27 @@
           clickOutsideToClose: true,
           escapeToClose: true,
           template: [
             '<md-dialog flex="40" flex-sm="80" flex-xs="100" aria-label="' + l('View Raw Source') + '">',
             '  <md-dialog-content class="md-dialog-content">',
-            '    <pre>',
-            data,
-            '    </pre>',
+            '    <pre ng-bind-html="data"></pre>',
             '  </md-dialog-content>',
             '  <md-dialog-actions>',
             '    <md-button ng-click="close()">' + l('Close') + '</md-button>',
             '  </md-dialog-actions>',
             '</md-dialog>'
           ].join(''),
-          controller: ComponentRawSourceDialogController
+          controller: ComponentRawSourceDialogController,
+          locals: { data: data }
         });
 
         /**
          * @ngInject
          */
-        ComponentRawSourceDialogController.$inject = ['scope', '$mdDialog'];
-        function ComponentRawSourceDialogController(scope, $mdDialog) {
+        ComponentRawSourceDialogController.$inject = ['scope', '$mdDialog', 'data'];
+        function ComponentRawSourceDialogController(scope, $mdDialog, data) {
+          scope.data = data;
           scope.close = function() {
             $mdDialog.hide();
           };
         }
       });

Vulnerable code:   [response appendContentString: content];
            '    <pre>',
            data,
            '    </pre>',
          controller: ComponentRawSourceDialogController
        ComponentRawSourceDialogController.$inject = ['scope', '$mdDialog'];
        function ComponentRawSourceDialogController(scope, $mdDialog) {
Fixed code:  - [web] properly encode events and tasks rawsource to avoid XSS issues (#3718)
  [response appendContentString: [content stringByEscapingHTMLString]];
            '    <pre ng-bind-html="data"></pre>',
          controller: ComponentRawSourceDialogController,
          locals: { data: data }
        ComponentRawSourceDialogController.$inject = ['scope', '$mdDialog', 'data'];
        function ComponentRawSourceDialogController(scope, $mdDialog, data) {
          scope.data = data;