From ce73b2754fb754c29d719c9980ae2f4aa4912f4d Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 4 May 2022 14:13:56 -0400 Subject: Ensure fenced code attributes are properly escaped. Fixes #1247. --- docs/change_log/index.md | 1 + markdown/extensions/fenced_code.py | 25 ++++++++++-------------- tests/test_syntax/extensions/test_fenced_code.py | 18 +++++++++++++++++ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/docs/change_log/index.md b/docs/change_log/index.md index 5320fc7..b9fa97b 100644 --- a/docs/change_log/index.md +++ b/docs/change_log/index.md @@ -7,6 +7,7 @@ Python-Markdown Change Log * Disallow square brackets in reference link ids (#1209). * Retain configured `pygments_style` after first code block (#1240). +* Ensure fenced code attributes are properly escaped (#1247). Nov 17, 2021: version 3.3.6 (a bug-fix release). diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py index 9be0ca0..409166a 100644 --- a/markdown/extensions/fenced_code.py +++ b/markdown/extensions/fenced_code.py @@ -22,6 +22,7 @@ from ..preprocessors import Preprocessor from .codehilite import CodeHilite, CodeHiliteExtension, parse_hl_lines from .attr_list import get_attrs, AttrListExtension from ..util import parseBoolValue +from ..serializers import _escape_attrib_html import re @@ -120,30 +121,24 @@ class FencedBlockPreprocessor(Preprocessor): else: id_attr = lang_attr = class_attr = kv_pairs = '' if lang: - lang_attr = ' class="{}{}"'.format(self.config.get('lang_prefix', 'language-'), lang) + prefix = self.config.get('lang_prefix', 'language-') + lang_attr = f' class="{prefix}{_escape_attrib_html(lang)}"' if classes: - class_attr = ' class="{}"'.format(' '.join(classes)) + class_attr = f' class="{_escape_attrib_html(" ".join(classes))}"' if id: - id_attr = ' id="{}"'.format(id) + id_attr = f' id="{_escape_attrib_html(id)}"' if self.use_attr_list and config and not config.get('use_pygments', False): # Only assign key/value pairs to code element if attr_list ext is enabled, key/value pairs # were defined on the code block, and the `use_pygments` key was not set to True. The # `use_pygments` key could be either set to False or not defined. It is omitted from output. - kv_pairs = ' ' + ' '.join( - '{k}="{v}"'.format(k=k, v=v) for k, v in config.items() if k != 'use_pygments' + kv_pairs = ''.join( + f' {k}="{_escape_attrib_html(v)}"' for k, v in config.items() if k != 'use_pygments' ) - code = '{code}'.format( - id=id_attr, - cls=class_attr, - lang=lang_attr, - kv=kv_pairs, - code=self._escape(m.group('code')) - ) + code = self._escape(m.group('code')) + code = f'{code}' placeholder = self.md.htmlStash.store(code) - text = '{}\n{}\n{}'.format(text[:m.start()], - placeholder, - text[m.end():]) + text = f'{text[:m.start()]}\n{placeholder}\n{text[m.end():]}' else: break return text.split("\n") diff --git a/tests/test_syntax/extensions/test_fenced_code.py b/tests/test_syntax/extensions/test_fenced_code.py index 76c8769..2cdde98 100644 --- a/tests/test_syntax/extensions/test_fenced_code.py +++ b/tests/test_syntax/extensions/test_fenced_code.py @@ -374,6 +374,24 @@ class TestFencedCode(TestCase): extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='lang-')] ) + def testFencedCodeEscapedAttrs(self): + self.assertMarkdownRenders( + self.dedent( + ''' + ``` { ."weird #"foo bar=">baz } + # Some python code + ``` + ''' + ), + self.dedent( + ''' +
# Some python code
+                
+ ''' + ), + extensions=['fenced_code', 'attr_list'] + ) + class TestFencedCodeWithCodehilite(TestCase): -- cgit v1.2.1