diff --git a/package.json b/package.json
index c25061fec70..ab451c78e39 100644
--- a/package.json
+++ b/package.json
@@ -95,7 +95,6 @@
"@types/jquery": "3.3.38",
"@types/lodash": "4.14.149",
"@types/lru-cache": "^5.1.0",
- "@types/marked": "1.1.0",
"@types/moment-timezone": "0.5.13",
"@types/mousetrap": "1.6.3",
"@types/node": "13.7.0",
@@ -247,7 +246,6 @@
"jsurl": "^0.1.5",
"lodash": "4.17.19",
"lru-cache": "^5.1.1",
- "marked": "1.1.1",
"md5": "^2.2.1",
"memoize-one": "5.1.1",
"moment": "2.24.0",
diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json
index f8d8a54c759..a72437fc971 100644
--- a/packages/grafana-data/package.json
+++ b/packages/grafana-data/package.json
@@ -28,6 +28,7 @@
"eventemitter3": "4.0.7",
"lodash": "4.17.19",
"rxjs": "6.6.3",
+ "marked": "1.2.2",
"xss": "1.0.6"
},
"devDependencies": {
@@ -40,6 +41,7 @@
"@types/jquery": "3.3.38",
"@types/lodash": "4.14.123",
"@types/node": "10.14.1",
+ "@types/marked": "1.1.0",
"@types/papaparse": "5.2.0",
"@types/react": "16.8.16",
"@types/rollup-plugin-visualizer": "2.6.0",
diff --git a/packages/grafana-data/src/text/markdown.test.ts b/packages/grafana-data/src/text/markdown.test.ts
index 3df231c77d4..ed51f2c28a2 100644
--- a/packages/grafana-data/src/text/markdown.test.ts
+++ b/packages/grafana-data/src/text/markdown.test.ts
@@ -5,4 +5,9 @@ describe('Markdown wrapper', () => {
const str = renderMarkdown(undefined);
expect(str).toBe('');
});
+
+ it('should sanitize by default', () => {
+ const str = renderMarkdown('');
+ expect(str).toBe('<script>alert()</script>');
+ });
});
diff --git a/packages/grafana-data/src/text/markdown.ts b/packages/grafana-data/src/text/markdown.ts
index f3c8d2f8981..4c9b369e291 100644
--- a/packages/grafana-data/src/text/markdown.ts
+++ b/packages/grafana-data/src/text/markdown.ts
@@ -1,19 +1,28 @@
-import marked, { MarkedOptions } from 'marked';
+import marked from 'marked';
+import { sanitize } from './sanitize';
-const defaultMarkedOptions: MarkedOptions = {
- renderer: new marked.Renderer(),
- pedantic: false,
- gfm: true,
- sanitize: true,
- smartLists: true,
- smartypants: false,
- xhtml: false,
-};
+let hasInitialized = false;
-export function setMarkdownOptions(optionsOverride?: MarkedOptions) {
- marked.setOptions({ ...defaultMarkedOptions, ...optionsOverride });
+export interface RenderMarkdownOptions {
+ noSanitize?: boolean;
}
-export function renderMarkdown(str?: string): string {
- return marked(str || '');
+export function renderMarkdown(str?: string, options?: RenderMarkdownOptions): string {
+ if (!hasInitialized) {
+ marked.setOptions({
+ pedantic: false,
+ gfm: true,
+ smartLists: true,
+ smartypants: false,
+ xhtml: false,
+ });
+ hasInitialized = true;
+ }
+
+ const html = marked(str || '');
+ if (options?.noSanitize) {
+ return html;
+ }
+
+ return sanitize(html);
}
diff --git a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx
index 235b1007c91..aa1f523542a 100644
--- a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx
@@ -2,7 +2,7 @@ import React, { useContext } from 'react';
import { css, cx } from 'emotion';
import { CompletionItem, selectThemeVariant, ThemeContext } from '../..';
-import { GrafanaTheme, renderMarkdown, textUtil } from '@grafana/data';
+import { GrafanaTheme, renderMarkdown } from '@grafana/data';
const getStyles = (theme: GrafanaTheme, height: number, visible: boolean) => {
return {
@@ -41,7 +41,7 @@ interface Props {
export const TypeaheadInfo: React.FC = ({ item, height }) => {
const visible = item && !!item.documentation;
const label = item ? item.label : '';
- const documentation = textUtil.sanitize(renderMarkdown(item?.documentation));
+ const documentation = renderMarkdown(item?.documentation);
const theme = useContext(ThemeContext);
const styles = getStyles(theme, height, visible);
diff --git a/public/app/app.ts b/public/app/app.ts
index 27d338def7a..3981ad7ef1c 100644
--- a/public/app/app.ts
+++ b/public/app/app.ts
@@ -28,7 +28,6 @@ import _ from 'lodash';
import {
AppEvents,
setLocale,
- setMarkdownOptions,
standardEditorsRegistry,
standardFieldConfigEditorRegistry,
standardTransformersRegistry,
@@ -97,8 +96,6 @@ export class GrafanaApp {
setLocale(config.bootData.user.locale);
setTimeZoneResolver(() => config.bootData.user.timezone);
- setMarkdownOptions({ sanitize: !config.disableSanitizeHtml });
-
standardEditorsRegistry.setInit(getStandardOptionEditors);
standardFieldConfigEditorRegistry.setInit(getStandardFieldConfigs);
standardTransformersRegistry.setInit(getStandardTransformers);
diff --git a/public/app/plugins/panel/text/TextPanel.tsx b/public/app/plugins/panel/text/TextPanel.tsx
index 5a7d374bdbe..de472f1c62c 100644
--- a/public/app/plugins/panel/text/TextPanel.tsx
+++ b/public/app/plugins/panel/text/TextPanel.tsx
@@ -43,7 +43,8 @@ export class TextPanel extends PureComponent {
}
prepareMarkdown(content: string): string {
- return renderMarkdown(this.interpolateAndSanitizeString(content));
+ // Sanitize is disabled here as we handle that after variable interpolation
+ return renderMarkdown(this.interpolateAndSanitizeString(content), { noSanitize: config.disableSanitizeHtml });
}
interpolateAndSanitizeString(content: string): string {
diff --git a/yarn.lock b/yarn.lock
index 0ea90d6aa93..abcb1a9be63 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -18229,10 +18229,10 @@ markdown-to-jsx@^6.11.4:
prop-types "^15.6.2"
unquote "^1.1.0"
-marked@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/marked/-/marked-1.1.1.tgz#e5d61b69842210d5df57b05856e0c91572703e6a"
- integrity sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==
+marked@1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-1.2.2.tgz#5d77ffb789c4cb0ae828bfe76250f7140b123f70"
+ integrity sha512-5jjKHVl/FPo0Z6ocP3zYhKiJLzkwJAw4CZoLjv57FkvbUuwOX4LIBBGGcXjAY6ATcd1q9B8UTj5T9Umauj0QYQ==
marked@^0.3.12:
version "0.3.19"