diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts
index 70129bebf55..420287c7a9b 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts
@@ -30,7 +30,7 @@ import {
BoxPlotQueryFormData,
EchartsBoxPlotChartProps,
} from './types';
-import { extractGroupbyLabel, getColtypesMapping } from '../utils/series';
+import { extractGroupbyLabel, getColtypesMapping, sanitizeHtml } from '../utils/series';
import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults';
export default function transformProps(
@@ -103,7 +103,9 @@ export default function transformProps(
tooltip: {
formatter: (param: { data: [string, number] }) => {
const [outlierName, stats] = param.data;
- const headline = groupby ? `
${outlierName}
` : '';
+ const headline = groupby
+ ? `${sanitizeHtml(outlierName)}
`
+ : '';
return `${headline}${numberFormatter(stats)}`;
},
},
@@ -161,7 +163,7 @@ export default function transformProps(
value: [number, number, number, number, number, number, number, number, number[]];
name: string;
} = param;
- const headline = name ? `${name}
` : '';
+ const headline = name ? `${sanitizeHtml(name)}
` : '';
const stats = [
`Max: ${numberFormatter(value[5])}`,
`3rd Quartile: ${numberFormatter(value[4])}`,
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts
index 5f15d849988..ee1772de204 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts
@@ -35,7 +35,12 @@ import {
FunnelChartTransformedProps,
} from './types';
import { DEFAULT_LEGEND_FORM_DATA } from '../types';
-import { extractGroupbyLabel, getChartPadding, getLegendProps } from '../utils/series';
+import {
+ extractGroupbyLabel,
+ getChartPadding,
+ getLegendProps,
+ sanitizeHtml,
+} from '../utils/series';
import { defaultGrid, defaultTooltip } from '../defaults';
const percentFormatter = getNumberFormatter(NumberFormats.PERCENT_2_POINT);
@@ -49,7 +54,8 @@ export function formatFunnelLabel({
labelType: EchartsFunnelLabelTypeType;
numberFormatter: NumberFormatter;
}): string {
- const { name = '', value, percent } = params;
+ const { name: rawName = '', value, percent } = params;
+ const name = sanitizeHtml(rawName);
const formattedValue = numberFormatter(value as number);
const formattedPercent = percentFormatter((percent as number) / 100);
switch (labelType) {
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts
index bfcf04b91a1..e3465512287 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts
@@ -34,7 +34,7 @@ import {
} from './types';
import { DEFAULT_GRAPH_SERIES_OPTION } from './constants';
import { EchartsProps } from '../types';
-import { getChartPadding, getLegendProps } from '../utils/series';
+import { getChartPadding, getLegendProps, sanitizeHtml } from '../utils/series';
type EdgeWithStyles = GraphEdgeItemOption & {
lineStyle: Exclude;
@@ -127,7 +127,9 @@ function edgeFormatter(
): string {
const source = Number(sourceIndex);
const target = Number(targetIndex);
- return `${getKeyByValue(nodes, source)} > ${getKeyByValue(nodes, target)} : ${value}`;
+ return `${sanitizeHtml(getKeyByValue(nodes, source))} > ${sanitizeHtml(
+ getKeyByValue(nodes, target),
+ )} : ${value}`;
}
function getCategoryName(columnName: string, name?: DataRecordValue) {
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts
index bfc240380bf..7cd47187cb1 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts
@@ -40,6 +40,7 @@ import {
getChartPadding,
getColtypesMapping,
getLegendProps,
+ sanitizeHtml,
} from '../utils/series';
import { defaultGrid, defaultTooltip } from '../defaults';
@@ -54,7 +55,8 @@ export function formatPieLabel({
labelType: EchartsPieLabelType;
numberFormatter: NumberFormatter;
}): string {
- const { name = '', value, percent } = params;
+ const { name: rawName = '', value, percent } = params;
+ const name = sanitizeHtml(rawName);
const formattedValue = numberFormatter(value as number);
const formattedPercent = percentFormatter((percent as number) / 100);
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts
index 86af47b19c6..2c23113864f 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts
@@ -20,6 +20,7 @@ import { TimeseriesDataRecord, NumberFormatter } from '@superset-ui/core';
import { CallbackDataParams, OptionName } from 'echarts/types/src/util/types';
import { TooltipMarker } from 'echarts/types/src/util/format';
import { ForecastSeriesContext, ForecastSeriesEnum, ProphetValue } from '../types';
+import { sanitizeHtml } from './series';
const seriesTypeRegex = new RegExp(
`(.+)(${ForecastSeriesEnum.ForecastLower}|${ForecastSeriesEnum.ForecastTrend}|${ForecastSeriesEnum.ForecastUpper})$`,
@@ -73,7 +74,7 @@ export const formatProphetTooltipSeries = ({
marker: TooltipMarker;
formatter: NumberFormatter;
}): string => {
- let row = `${marker}${seriesName}: `;
+ let row = `${marker}${sanitizeHtml(seriesName)}: `;
let isObservation = false;
if (observation) {
isObservation = true;
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts
index 2cb7ad4b9a5..0e1db573ba8 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts
@@ -26,7 +26,7 @@ import {
TimeFormatter,
TimeseriesDataRecord,
} from '@superset-ui/core';
-import { LegendComponentOption, SeriesOption } from 'echarts';
+import { format, LegendComponentOption, SeriesOption } from 'echarts';
import { NULL_STRING, TIMESERIES_CONSTANTS } from '../constants';
import { LegendOrientation, LegendType } from '../types';
import { defaultLegendPadding } from '../defaults';
@@ -200,3 +200,7 @@ export function dedupSeries(series: SeriesOption[]): SeriesOption[] {
};
});
}
+
+export function sanitizeHtml(text: string): string {
+ return format.encodeHTML(text);
+}
diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts
index c0f3a3b87d5..d5d3dd89fa2 100644
--- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts
+++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts
@@ -24,9 +24,11 @@ import {
formatSeriesName,
getChartPadding,
getLegendProps,
+ sanitizeHtml,
} from '../../src/utils/series';
import { LegendOrientation, LegendType } from '../../src/types';
import { defaultLegendPadding } from '../../src/defaults';
+import { NULL_STRING } from '../../lib/constants';
describe('extractTimeseriesSeries', () => {
it('should generate a valid ECharts timeseries series object', () => {
@@ -350,4 +352,10 @@ describe('formatSeriesName', () => {
).toEqual([{ id: 'foo' }, { id: 'bar' }, { id: 'foo (1)' }, { id: 'foo (2)' }]);
});
});
+
+ describe('sanitizeHtml', () => {
+ it('should remove html tags from series name', () => {
+ expect(sanitizeHtml(NULL_STRING)).toEqual('<NULL>');
+ });
+ });
});