Browse Source

Mitigate XSS vulnerabilities in Singlestat panel

Sanitize `prefix` and `postfix` fields. Re-arrange code slightly in order to handle variable
interpolation.
Victor Cinaglia 7 years ago
parent
commit
ba5a002323

+ 10 - 20
public/app/plugins/panel/singlestat/module.ts

@@ -77,7 +77,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
   };
 
   /** @ngInject */
-  constructor($scope, $injector, private linkSrv) {
+  constructor($scope, $injector, private linkSrv, private $sanitize) {
     super($scope, $injector);
     _.defaults(this.panel, this.panelDefaults);
 
@@ -398,14 +398,15 @@ class SingleStatCtrl extends MetricsPanelCtrl {
     const $location = this.$location;
     const linkSrv = this.linkSrv;
     const $timeout = this.$timeout;
+    const $sanitize = this.$sanitize;
     const panel = ctrl.panel;
     const templateSrv = this.templateSrv;
     let data, linkInfo;
     const $panelContainer = elem.find('.panel-container');
     elem = elem.find('.singlestat-panel');
 
-    function applyColoringThresholds(value, valueString) {
-      const color = getColorForValue(data, value);
+    function applyColoringThresholds(valueString) {
+      const color = getColorForValue(data, data.value);
       if (color) {
         return '<span style="color:' + color + '">' + valueString + '</span>';
       }
@@ -413,8 +414,9 @@ class SingleStatCtrl extends MetricsPanelCtrl {
       return valueString;
     }
 
-    function getSpan(className, fontSize, value) {
-      value = templateSrv.replace(value, data.scopedVars);
+    function getSpan(className, fontSize, applyColoring, value) {
+      value = $sanitize(templateSrv.replace(value, data.scopedVars));
+      value = applyColoring ? applyColoringThresholds(value) : value;
       return '<span class="' + className + '" style="font-size:' + fontSize + '">' + value + '</span>';
     }
 
@@ -422,25 +424,13 @@ class SingleStatCtrl extends MetricsPanelCtrl {
       let body = '<div class="singlestat-panel-value-container">';
 
       if (panel.prefix) {
-        let prefix = panel.prefix;
-        if (panel.colorPrefix) {
-          prefix = applyColoringThresholds(data.value, panel.prefix);
-        }
-        body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, prefix);
+        body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, panel.colorPrefix, panel.prefix);
       }
 
-      let value = data.valueFormatted;
-      if (panel.colorValue) {
-        value = applyColoringThresholds(data.value, value);
-      }
-      body += getSpan('singlestat-panel-value', panel.valueFontSize, value);
+      body += getSpan('singlestat-panel-value', panel.valueFontSize, panel.colorValue, data.valueFormatted);
 
       if (panel.postfix) {
-        let postfix = panel.postfix;
-        if (panel.colorPostfix) {
-          postfix = applyColoringThresholds(data.value, panel.postfix);
-        }
-        body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, postfix);
+        body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.colorPostfix, panel.postfix);
       }
 
       body += '</div>';

+ 3 - 1
public/app/plugins/panel/singlestat/specs/singlestat.test.ts

@@ -14,6 +14,8 @@ describe('SingleStatCtrl', () => {
     get: () => {},
   };
 
+  const $sanitize = {};
+
   SingleStatCtrl.prototype.panel = {
     events: {
       on: () => {},
@@ -31,7 +33,7 @@ describe('SingleStatCtrl', () => {
     describe(desc, () => {
       ctx.setup = setupFunc => {
         beforeEach(() => {
-          ctx.ctrl = new SingleStatCtrl($scope, $injector, {});
+          ctx.ctrl = new SingleStatCtrl($scope, $injector, {}, $sanitize);
           setupFunc();
           ctx.ctrl.onDataReceived(ctx.data);
           ctx.data = ctx.ctrl.data;