diff --git a/CHANGES.md b/CHANGES.md index afb0be54..a77bd029 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 diff --git a/lib/markdown2.py b/lib/markdown2.py index e35bf5d2..0e13c689 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -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 `` 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'ok img

-

img

+

img

img2

-

img3

+

img3

<img src="javascript:alert(1)"

diff --git a/test/tm-cases/image_safe_urls.html b/test/tm-cases/image_safe_urls.html new file mode 100644 index 00000000..5517dfe2 --- /dev/null +++ b/test/tm-cases/image_safe_urls.html @@ -0,0 +1,25 @@ +

Safe images

+ +

Safe image 1

+ +

Safe image 2

+ +

Safe image 3

+ +

Bad protocols

+ +

Unsafe image 1

+ +

Unsafe image 2

+ +

Unsafe image 3

+ +

Unsafe image 4

+ +

Reference images

+ +

Safe ref

+ +

Unsafe ref

+ +

Unsafe image 5

diff --git a/test/tm-cases/image_safe_urls.opts b/test/tm-cases/image_safe_urls.opts new file mode 100644 index 00000000..ad487c04 --- /dev/null +++ b/test/tm-cases/image_safe_urls.opts @@ -0,0 +1 @@ +{"safe_mode": "escape"} diff --git a/test/tm-cases/image_safe_urls.tags b/test/tm-cases/image_safe_urls.tags new file mode 100644 index 00000000..02abe816 --- /dev/null +++ b/test/tm-cases/image_safe_urls.tags @@ -0,0 +1 @@ +safe_mode diff --git a/test/tm-cases/image_safe_urls.text b/test/tm-cases/image_safe_urls.text new file mode 100644 index 00000000..ebf267ba --- /dev/null +++ b/test/tm-cases/image_safe_urls.text @@ -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)//`) diff --git a/test/tm-cases/issue603_xss.html b/test/tm-cases/issue603_xss.html index 2293d586..9ca2bc7b 100644 --- a/test/tm-cases/issue603_xss.html +++ b/test/tm-cases/issue603_xss.html @@ -1,6 +1,6 @@ -

+

-

+

- -

+ +

diff --git a/test/tm-cases/xss_code_spans_issue726.html b/test/tm-cases/xss_code_spans_issue726.html index de01da01..06f8edcf 100644 --- a/test/tm-cases/xss_code_spans_issue726.html +++ b/test/tm-cases/xss_code_spans_issue726.html @@ -1,6 +1,4 @@ -

<x><svg onload=alert(origin)

+

<x><svg onload=alert(origin)

Code spans still come out escaped once: a<b, <b> and C:\<folder>

diff --git a/test/tm-cases/xss_smuggling_spans_in_image_attrs.html b/test/tm-cases/xss_smuggling_spans_in_image_attrs.html index c0837ef9..1b78de92 100644 --- a/test/tm-cases/xss_smuggling_spans_in_image_attrs.html +++ b/test/tm-cases/xss_smuggling_spans_in_image_attrs.html @@ -1,6 +1,6 @@

-

<code>" onerror="alert(1)//</code>

+

<code>" onerror="alert(1)//</code>

A

@@ -13,11 +13,10 @@
  • onerror=alert(origin) )
  • -

    +

    http://onclick=alert(origin)//![](x)

    http://onclick=alert(origin)//[<codeClick me]()>

    -

    ![x](<"`"x

    +

    ![x](<"`"x