Skip to content

Commit ded5e74

Browse files
Merge pull request #604 from Crozzers/fix-xss-603
Fix XSS injection in image URLs (#603)
2 parents 1e0fbf2 + 1b3d705 commit ded5e74

File tree

5 files changed

+40
-5
lines changed

5 files changed

+40
-5
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [pull #590] Fix underscores within bold text getting emphasized (#589)
66
- [pull #591] Add Alerts extra
77
- [pull #595] Fix img alt text being processed as markdown (#594)
8+
- [pull #604] Fix XSS injection in image URLs (#603)
89

910

1011
## python-markdown2 2.5.0

lib/markdown2.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,9 +1354,23 @@ def _is_comment(token):
13541354
is_html_markup = not is_html_markup
13551355
return ''.join(tokens)
13561356

1357-
def _unhash_html_spans(self, text: str) -> str:
1358-
for key, sanitized in list(self.html_spans.items()):
1359-
text = text.replace(key, sanitized)
1357+
def _unhash_html_spans(self, text: str, spans=True, code=False) -> str:
1358+
'''
1359+
Recursively unhash a block of text
1360+
1361+
Args:
1362+
spans: unhash anything from `self.html_spans`
1363+
code: unhash code blocks
1364+
'''
1365+
orig = ''
1366+
while text != orig:
1367+
if spans:
1368+
for key, sanitized in list(self.html_spans.items()):
1369+
text = text.replace(key, sanitized)
1370+
if code:
1371+
for code, key in list(self._code_table.items()):
1372+
text = text.replace(key, code)
1373+
orig = text
13601374
return text
13611375

13621376
def _sanitize_html(self, s: str) -> str:
@@ -1582,8 +1596,9 @@ def _do_links(self, text: str) -> str:
15821596

15831597
# We've got to encode these to avoid conflicting
15841598
# with italics/bold.
1585-
url = url.replace('*', self._escape_table['*']) \
1586-
.replace('_', self._escape_table['_'])
1599+
url = self._unhash_html_spans(url, code=True) \
1600+
.replace('*', self._escape_table['*']) \
1601+
.replace('_', self._escape_table['_'])
15871602
if title:
15881603
title_str = ' title="%s"' % (
15891604
_xml_escape_attr(title)

test/tm-cases/issue603_xss.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<p><img src="code&gt;&quot; onerror=alert()//&lt;/code" alt="" /></p>
2+
3+
<p><img src="&quot; onerror=alert()//" alt="" />
4+
<a href="#"></a>
5+
<img src="`&quot; onerror=alert()//`" alt="" />
6+
<img src="&lt;code&gt;&quot; onerror=alert()//&lt;code&gt;" alt="" /></p>

test/tm-cases/issue603_xss.opts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"safe_mode": "escape"}

test/tm-cases/issue603_xss.text

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
![](`" onerror=alert()//`)
2+
3+
4+
![][XSS]
5+
[][XSS]
6+
![][XSS2]
7+
![][XSS3]
8+
9+
10+
[XSS]: " onerror=alert()//
11+
[XSS2]: `" onerror=alert()//`
12+
[XSS3]: <code>" onerror=alert()//<code>

0 commit comments

Comments
 (0)