From b6338611aafba3eefb645faa487d7393a65e1b97 Mon Sep 17 00:00:00 2001 From: Crozzers Date: Sun, 22 Sep 2024 19:21:19 +0100 Subject: [PATCH 1/2] Fix XSS injection in image URLs (#603) --- CHANGES.md | 1 + lib/markdown2.py | 25 ++++++++++++++++++++----- test/tm-cases/issue603_xss.html | 4 ++++ test/tm-cases/issue603_xss.opts | 1 + test/tm-cases/issue603_xss.text | 8 ++++++++ 5 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 test/tm-cases/issue603_xss.html create mode 100644 test/tm-cases/issue603_xss.opts create mode 100644 test/tm-cases/issue603_xss.text diff --git a/CHANGES.md b/CHANGES.md index 4283b966..f07fb095 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ - [pull #590] Fix underscores within bold text getting emphasized (#589) - [pull #591] Add Alerts extra - [pull #595] Fix img alt text being processed as markdown (#594) +- [pull #604] Fix XSS injection in image URLs (#603) ## python-markdown2 2.5.0 diff --git a/lib/markdown2.py b/lib/markdown2.py index d0f10eea..26e5b075 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -1354,9 +1354,23 @@ def _is_comment(token): is_html_markup = not is_html_markup return ''.join(tokens) - def _unhash_html_spans(self, text: str) -> str: - for key, sanitized in list(self.html_spans.items()): - text = text.replace(key, sanitized) + def _unhash_html_spans(self, text: str, spans=True, code=False) -> str: + ''' + Recursively unhash a block of text + + Args: + spans: unhash anything from `self.html_spans` + code: unhash code blocks + ''' + orig = '' + while text != orig: + if spans: + for key, sanitized in list(self.html_spans.items()): + text = text.replace(key, sanitized) + if code: + for code, key in list(self._code_table.items()): + text = text.replace(key, code) + orig = text return text def _sanitize_html(self, s: str) -> str: @@ -1582,8 +1596,9 @@ def _do_links(self, text: str) -> str: # We've got to encode these to avoid conflicting # with italics/bold. - url = url.replace('*', self._escape_table['*']) \ - .replace('_', self._escape_table['_']) + url = self._unhash_html_spans(url, code=True) \ + .replace('*', self._escape_table['*']) \ + .replace('_', self._escape_table['_']) if title: title_str = ' title="%s"' % ( _xml_escape_attr(title) diff --git a/test/tm-cases/issue603_xss.html b/test/tm-cases/issue603_xss.html new file mode 100644 index 00000000..12d22fdb --- /dev/null +++ b/test/tm-cases/issue603_xss.html @@ -0,0 +1,4 @@ +

+ +

+

diff --git a/test/tm-cases/issue603_xss.opts b/test/tm-cases/issue603_xss.opts new file mode 100644 index 00000000..ad487c04 --- /dev/null +++ b/test/tm-cases/issue603_xss.opts @@ -0,0 +1 @@ +{"safe_mode": "escape"} diff --git a/test/tm-cases/issue603_xss.text b/test/tm-cases/issue603_xss.text new file mode 100644 index 00000000..cbb0fdf8 --- /dev/null +++ b/test/tm-cases/issue603_xss.text @@ -0,0 +1,8 @@ +![](`" onerror=alert()//`) + + +![][XSS] +[][XSS] + + +[XSS]: " onerror=alert()// From 1b3d7057492adee781ad1a54fef176efd7d46868 Mon Sep 17 00:00:00 2001 From: Crozzers Date: Sun, 22 Sep 2024 19:28:15 +0100 Subject: [PATCH 2/2] Expand link shortcut tests in XSS issue 604 case --- test/tm-cases/issue603_xss.html | 4 +++- test/tm-cases/issue603_xss.text | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/tm-cases/issue603_xss.html b/test/tm-cases/issue603_xss.html index 12d22fdb..2293d586 100644 --- a/test/tm-cases/issue603_xss.html +++ b/test/tm-cases/issue603_xss.html @@ -1,4 +1,6 @@

-

+ + +

diff --git a/test/tm-cases/issue603_xss.text b/test/tm-cases/issue603_xss.text index cbb0fdf8..85835be0 100644 --- a/test/tm-cases/issue603_xss.text +++ b/test/tm-cases/issue603_xss.text @@ -3,6 +3,10 @@ ![][XSS] [][XSS] +![][XSS2] +![][XSS3] [XSS]: " onerror=alert()// +[XSS2]: `" onerror=alert()//` +[XSS3]: " onerror=alert()//