From c1c074b88f7ad5a2eeb5eb9e12dde02fc4544946 Mon Sep 17 00:00:00 2001 From: CatNose <34590683+catnose99@users.noreply.github.com> Date: Wed, 30 Sep 2020 01:20:33 +0900 Subject: [PATCH] fix: escape the language class name so it cannot be used to inject HTML (#137) * fix: fix: escape lang to use * test: add unit test for XSS injection through the language name * test: make the XSS attack test more realistic Co-authored-by: Joshua Gleitze --- src/index.ts | 2 +- test/test.ts | 8 +++++++- testdata/expected/fenced-with-html-in-language.html | 8 ++++++++ testdata/input/fenced-with-html-in-language.md | 11 +++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 testdata/expected/fenced-with-html-in-language.html create mode 100644 testdata/input/fenced-with-html-in-language.md diff --git a/src/index.ts b/src/index.ts index fb2e55e0..f439ce30 100644 --- a/src/index.ts +++ b/src/index.ts @@ -106,7 +106,7 @@ function selectLanguage(options: Options, lang: string): [string, Grammar | unde function highlight(markdownit: MarkdownIt, options: Options, text: string, lang: string): string { const [langToUse, prismLang] = selectLanguage(options, lang) const code = prismLang ? Prism.highlight(text, prismLang, langToUse) : markdownit.utils.escapeHtml(text) - const classAttribute = langToUse ? ` class="${markdownit.options.langPrefix}${langToUse}"` : '' + const classAttribute = langToUse ? ` class="${markdownit.options.langPrefix}${markdownit.utils.escapeHtml(langToUse)}"` : '' return `${code}` } diff --git a/test/test.ts b/test/test.ts index dc4831e6..7d01b604 100644 --- a/test/test.ts +++ b/test/test.ts @@ -80,7 +80,6 @@ describe('markdown-it-prism', () => { .use(markdownItPrism) .render(await read('input/indented.md')) ).toEqual(await read('expected/indented.html')) - }) it('adds classes even if the language is unknown', async () => { @@ -90,6 +89,13 @@ describe('markdown-it-prism', () => { ).toEqual(await read('expected/fenced-with-unknown-language.html')) }) + it('escapes HTML in the language name', async () => { + expect(markdownit() + .use(markdownItPrism) + .render(await read('input/fenced-with-html-in-language.md')) + ).toEqual(await read('expected/fenced-with-html-in-language.html')) + }) + it('falls back to defaultLanguageForUnknown if the specified language is unknown', async () => { expect(markdownit() .use(markdownItPrism, { diff --git a/testdata/expected/fenced-with-html-in-language.html b/testdata/expected/fenced-with-html-in-language.html new file mode 100644 index 00000000..8377baff --- /dev/null +++ b/testdata/expected/fenced-with-html-in-language.html @@ -0,0 +1,8 @@ +

Test

+

This is a fenced code block:

+
public class Foo() {
+	public Foo(bar) {
+		System.out.println(bar);
+	}
+}
+
diff --git a/testdata/input/fenced-with-html-in-language.md b/testdata/input/fenced-with-html-in-language.md new file mode 100644 index 00000000..9c645a36 --- /dev/null +++ b/testdata/input/fenced-with-html-in-language.md @@ -0,0 +1,11 @@ +# Test + +This is a fenced code block: + +```">