Skip to content

Commit

Permalink
Merge pull request #20045 from apache/fix/tooltip-xss
Browse files Browse the repository at this point in the history
fix(tooltip): fix tooltip XSS issue when legend name is HTML string
  • Loading branch information
plainheart committed Jun 19, 2024
2 parents 9d2bab0 + 6221076 commit efa3e5a
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 25 deletions.
14 changes: 13 additions & 1 deletion src/component/tooltip/TooltipView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { bind, each, clone, trim, isString, isFunction, isArray, isObject, exten
import env from 'zrender/src/core/env';
import TooltipHTMLContent from './TooltipHTMLContent';
import TooltipRichContent from './TooltipRichContent';
import { convertToColorString, formatTpl, TooltipMarker } from '../../util/format';
import { convertToColorString, encodeHTML, formatTpl, TooltipMarker } from '../../util/format';
import { parsePercent } from '../../util/number';
import { Rect } from '../../util/graphic';
import findPointFromSeries from '../axisPointer/findPointFromSeries';
Expand Down Expand Up @@ -724,16 +724,28 @@ class TooltipView extends ComponentView {
el: ECElement,
dispatchAction: ExtensionAPI['dispatchAction']
) {
const isHTMLRenderMode = this._renderMode === 'html';
const ecData = getECData(el);
const tooltipConfig = ecData.tooltipConfig;
let tooltipOpt = tooltipConfig.option || {};
let encodeHTMLContent = tooltipOpt.encodeHTMLContent;
if (isString(tooltipOpt)) {
const content = tooltipOpt;
tooltipOpt = {
content: content,
// Fixed formatter
formatter: content
};
// when `tooltipConfig.option` is a string rather than an object,
// we can't know if the content needs to be encoded
// for the sake of security, encode it by default.
encodeHTMLContent = true;
}

if (encodeHTMLContent && isHTMLRenderMode && tooltipOpt.content) {
// clone might be unnecessary?
tooltipOpt = clone(tooltipOpt);
tooltipOpt.content = encodeHTML(tooltipOpt.content);
}

const tooltipModelCascade = [tooltipOpt] as TooltipModelOptionCascade[];
Expand Down
2 changes: 1 addition & 1 deletion src/util/graphic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ import {
import { getECData } from './innerStore';
import ComponentModel from '../model/Component';


import {
updateProps,
initProps,
Expand Down Expand Up @@ -604,6 +603,7 @@ export function setTooltipConfig(opt: {
name: itemName,
option: defaults({
content: itemName,
encodeHTMLContent: true,
formatterParams: formatterParams
}, itemTooltipOptionObj)
};
Expand Down
6 changes: 6 additions & 0 deletions src/util/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,12 @@ export interface CommonTooltipOption<FormatterParams> {
export type ComponentItemTooltipOption<T> = CommonTooltipOption<T> & {
// Default content HTML.
content?: string;
/**
* Whether to encode HTML content according to `tooltip.renderMode`.
*
* e.g. renderMode 'html' needs to encode but 'richText' does not.
*/
encodeHTMLContent?: boolean;
formatterParams?: ComponentItemTooltipLabelFormatterParams;
};
export type ComponentItemTooltipLabelFormatterParams = {
Expand Down
2 changes: 1 addition & 1 deletion test/runTest/actions/__meta__.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/runTest/actions/tooltip.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit efa3e5a

Please sign in to comment.