Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- [pull #743] Add a `strip-syntax` option to the `header-ids` extra that leaves link URLs, image paths, inline HTML tags and emphasis markers out of header ids (#192)
- [pull #747] Fix `link-patterns` extra linking text inside Markdown links and images whose label wraps onto another line
- [pull #759] Fix `fenced-code-blocks` extra not recognizing code blocks whose language name contains `#` or `.`, such as `c#`, `f#` and `vb.net`
- [pull #766] Fix `safe_mode` allowing `javascript:` and other unsafe URLs in image sources (#764)


## python-markdown2 2.5.5
Expand Down
11 changes: 11 additions & 0 deletions lib/markdown2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3248,6 +3248,17 @@ def process_image(self, url: str, title_attr: str, link_text: str) -> Tuple[str,
2. The length of the opening HTML tag in the string. For `<img>` it's the whole string.
This section will be skipped by the link processor
'''
if self.md.safe_mode and not self.md._safe_href.match(url):
# same check as links, but keep allowing base64 image data URLs
data_url = self.md._data_url_re.match(url)
if not (
data_url
and (data_url.group('mime') or '').startswith('image/')
and data_url.group('token') == ';base64'
and re.fullmatch(r'[A-Za-z0-9+/=]*', data_url.group('data'))
):
url = '#'

img_class_str = self.md._html_class_str_from_tag("img")
result = (
f'<img src="{self.md._protect_url(url)}"'
Expand Down
4 changes: 2 additions & 2 deletions test/tm-cases/basic_safe_mode.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@

<p><img src="http://example.com/image.gif?h=200&amp;w=500" alt="ok img" /></p>

<p><img src="http://example.com&quot;onclick=&quot;alert(1)" alt="img" /></p>
<p><img src="#" alt="img" /></p>

<p><img src="http://example.com" alt="img2" title="text&quot;onclick=&quot;alert(1)" /></p>

<p><img src="http://example.com&gt;[HTML_REMOVED]alert(1)[HTML_REMOVED]" alt="img3" /></p>
<p><img src="#" alt="img3" /></p>

<p>&lt;img src="javascript:alert(1)"</p>

Expand Down
25 changes: 25 additions & 0 deletions test/tm-cases/image_safe_urls.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<h1>Safe images</h1>

<p><img src="https://www.example.com/a.png" alt="Safe image 1" /></p>

<p><img src="/a.png" alt="Safe image 2" /></p>

<p><img src="data:image/png;base64,iVBORw0KGgo=" alt="Safe image 3" /></p>

<h1>Bad protocols</h1>

<p><img src="#" alt="Unsafe image 1" /></p>

<p><img src="#" alt="Unsafe image 2" /></p>

<p><img src="#" alt="Unsafe image 3" /></p>

<p><img src="#" alt="Unsafe image 4" /></p>

<h1>Reference images</h1>

<p><img src="https://www.example.com/a.png" alt="Safe ref" /></p>

<p><img src="#" alt="Unsafe ref" /></p>

<p><img src="#" alt="Unsafe image 5" /></p>
1 change: 1 addition & 0 deletions test/tm-cases/image_safe_urls.opts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"safe_mode": "escape"}
1 change: 1 addition & 0 deletions test/tm-cases/image_safe_urls.tags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
safe_mode
28 changes: 28 additions & 0 deletions test/tm-cases/image_safe_urls.text
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Safe images

![Safe image 1](https://www.example.com/a.png)

![Safe image 2](/a.png)

![Safe image 3](data:image/png;base64,iVBORw0KGgo=)

# Bad protocols

![Unsafe image 1](javascript:alert(1))

![Unsafe image 2](JaVaScRiPt:alert(1))

![Unsafe image 3](vbscript:msgbox(1))

![Unsafe image 4](data:text/html,hello)

# Reference images

![Safe ref][safe]

![Unsafe ref][unsafe]

[safe]: https://www.example.com/a.png
[unsafe]: javascript:alert(1)

![Unsafe image 5](data:image/png;base64,`x" onerror="alert(1)//`)
8 changes: 4 additions & 4 deletions test/tm-cases/issue603_xss.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<p><img src="code&gt;&quot; onerror=alert()//&lt;/code" alt="" /></p>
<p><img src="#" alt="" /></p>

<p><img src="&quot; onerror=alert()//" alt="" />
<p><img src="#" alt="" />
<a href="#"></a>
<img src="`&quot; onerror=alert()//`" alt="" />
<img src="&lt;code&gt;&quot; onerror=alert()//&lt;code&gt;" alt="" /></p>
<img src="#" alt="" />
<img src="#" alt="" /></p>
4 changes: 1 addition & 3 deletions test/tm-cases/xss_code_spans_issue726.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<p>&lt;x<img src="code&gt;&lt;a
&gt;&lt;/code" alt="" />&gt;&lt;svg onload=alert(origin)<img src="code&gt;&lt;a
&gt;&lt;/code" alt="" /></p>
<p>&lt;x<img src="#" alt="" />&gt;&lt;svg onload=alert(origin)<img src="#" alt="" /></p>

<p>Code spans still come out escaped once: <code>a&lt;b</code>, <code>&lt;b&gt;</code> and <code>C:\&lt;folder&gt;</code></p>

Expand Down
7 changes: 3 additions & 4 deletions test/tm-cases/xss_smuggling_spans_in_image_attrs.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<p><img src="x" alt="" title="&lt;code&gt;&quot; onerror=alert(1)//&lt;/code&gt;&quot;" /></p>

<p><img src="" alt="&lt;code&gt;&quot; onerror=&quot;alert(1)//&lt;/code&gt;" /></p>
<p><img src="#" alt="&lt;code&gt;&quot; onerror=&quot;alert(1)//&lt;/code&gt;" /></p>

<p><img src="B" alt="A" title="&lt;C D=&quot;E&quot; onerror=alert(origin) &gt;" /></p>

Expand All @@ -13,11 +13,10 @@
<li><img src="x" alt="" title="&lt;code&gt;![](&lt;/code&gt;" /> onerror=alert(origin) )</li>
</ul>

<p><img src="code&gt;&lt;A B=&quot;
&quot; onerror=&quot;alert(origin)&quot;&gt;&lt;/code" alt="" /></p>
<p><img src="#" alt="" /></p>

<p><a href="http://onclick=alert(origin)//![](x)">http://onclick=alert(origin)//![](x)</a></p>

<p><a href="http://onclick=alert(origin)//[&lt;code">http://onclick=alert(origin)//[&lt;code</a>Click me</code>]()&gt;</p>

<p>![x](&lt;"`"<img src="x &quot;&lt;A B=&quot;&quot; onerror=&quot;alert(origin)&quot;&gt;`" alt="x" /></p>
<p>![x](&lt;"`"<img src="#" alt="x" /></p>
Loading