Skip to content

Commit efa3e5a

Browse files
authored
Merge pull request #20045 from apache/fix/tooltip-xss
fix(tooltip): fix tooltip XSS issue when legend name is HTML string
2 parents 9d2bab0 + 6221076 commit efa3e5a

File tree

6 files changed

+77
-25
lines changed

6 files changed

+77
-25
lines changed

src/component/tooltip/TooltipView.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { bind, each, clone, trim, isString, isFunction, isArray, isObject, exten
2020
import env from 'zrender/src/core/env';
2121
import TooltipHTMLContent from './TooltipHTMLContent';
2222
import TooltipRichContent from './TooltipRichContent';
23-
import { convertToColorString, formatTpl, TooltipMarker } from '../../util/format';
23+
import { convertToColorString, encodeHTML, formatTpl, TooltipMarker } from '../../util/format';
2424
import { parsePercent } from '../../util/number';
2525
import { Rect } from '../../util/graphic';
2626
import findPointFromSeries from '../axisPointer/findPointFromSeries';
@@ -724,16 +724,28 @@ class TooltipView extends ComponentView {
724724
el: ECElement,
725725
dispatchAction: ExtensionAPI['dispatchAction']
726726
) {
727+
const isHTMLRenderMode = this._renderMode === 'html';
727728
const ecData = getECData(el);
728729
const tooltipConfig = ecData.tooltipConfig;
729730
let tooltipOpt = tooltipConfig.option || {};
731+
let encodeHTMLContent = tooltipOpt.encodeHTMLContent;
730732
if (isString(tooltipOpt)) {
731733
const content = tooltipOpt;
732734
tooltipOpt = {
733735
content: content,
734736
// Fixed formatter
735737
formatter: content
736738
};
739+
// when `tooltipConfig.option` is a string rather than an object,
740+
// we can't know if the content needs to be encoded
741+
// for the sake of security, encode it by default.
742+
encodeHTMLContent = true;
743+
}
744+
745+
if (encodeHTMLContent && isHTMLRenderMode && tooltipOpt.content) {
746+
// clone might be unnecessary?
747+
tooltipOpt = clone(tooltipOpt);
748+
tooltipOpt.content = encodeHTML(tooltipOpt.content);
737749
}
738750

739751
const tooltipModelCascade = [tooltipOpt] as TooltipModelOptionCascade[];

src/util/graphic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ import {
6868
import { getECData } from './innerStore';
6969
import ComponentModel from '../model/Component';
7070

71-
7271
import {
7372
updateProps,
7473
initProps,
@@ -604,6 +603,7 @@ export function setTooltipConfig(opt: {
604603
name: itemName,
605604
option: defaults({
606605
content: itemName,
606+
encodeHTMLContent: true,
607607
formatterParams: formatterParams
608608
}, itemTooltipOptionObj)
609609
};

src/util/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,12 @@ export interface CommonTooltipOption<FormatterParams> {
13361336
export type ComponentItemTooltipOption<T> = CommonTooltipOption<T> & {
13371337
// Default content HTML.
13381338
content?: string;
1339+
/**
1340+
* Whether to encode HTML content according to `tooltip.renderMode`.
1341+
*
1342+
* e.g. renderMode 'html' needs to encode but 'richText' does not.
1343+
*/
1344+
encodeHTMLContent?: boolean;
13391345
formatterParams?: ComponentItemTooltipLabelFormatterParams;
13401346
};
13411347
export type ComponentItemTooltipLabelFormatterParams = {

test/runTest/actions/__meta__.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/runTest/actions/tooltip.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)