Repository: trentm/python-markdown2 (language: python)

Issue:
Safe mode XSS
**Describe the bug**
It's possible to bypass the safe mode (escape and replace) 

**To Reproduce**
Create a file called PoC.html:

```html
<img src=# onerror="alert()"></p>
```

Then, execute
```sh
markdown2 --safe escape PoC.html > result.html
```
The content of `result.html` will be:
```html
<p><img src=# onerror="alert()">&lt;/p&gt;</p>
```

Note that the `<img>` tag has not been escaped.
Finally, open `result.html` with a browser and you should see a pop up.

**Expected behavior**
All dangerous characters should be escaped.

**Debug info**
Version of library being used: 2.5.0

**Additional context**
no


Discussion / hints:

Fix patch:
diff --git a/CHANGES.md b/CHANGES.md
index f07fb095..66a15743 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 #602] Fix XSS issue in safe mode (#601)
 - [pull #604] Fix XSS injection in image URLs (#603)
 
 
diff --git a/lib/markdown2.py b/lib/markdown2.py
index 26e5b075..5d8106fc 100755
--- a/lib/markdown2.py
+++ b/lib/markdown2.py
@@ -1260,8 +1260,13 @@ def _run_span_gamut(self, text: str) -> str:
             (?:
                 # tag
                 </?
-                (?:\w+)                                     # tag name
-                (?:\s+(?:[\w-]+:)?[\w-]+=(?:".*?"|'.*?'))*  # attributes
+                (?:\w+)         # tag name
+                (?:             # attributes
+                    \s+                           # whitespace after tag
+                    (?:[^\t<>"'=/]+:)?
+                    [^<>"'=/]+=                   # attr name
+                    (?:".*?"|'.*?'|[^<>"'=/\s]+)  # value, quoted or unquoted. If unquoted, no spaces allowed
+                )*
                 \s*/?>
                 |
                 # auto-link (e.g., <http://www.activestate.com/>)


Test patch:
diff --git a/test/tm-cases/issue601_xss.html b/test/tm-cases/issue601_xss.html
new file mode 100644
index 00000000..e369d54e
--- /dev/null
+++ b/test/tm-cases/issue601_xss.html
@@ -0,0 +1,1 @@
+<p>&lt;img src=# onerror="alert()"&gt;&lt;/p&gt;</p>
diff --git a/test/tm-cases/issue601_xss.opts b/test/tm-cases/issue601_xss.opts
new file mode 100644
index 00000000..ad487c04
--- /dev/null
+++ b/test/tm-cases/issue601_xss.opts
@@ -0,0 +1,1 @@
+{"safe_mode": "escape"}
diff --git a/test/tm-cases/issue601_xss.text b/test/tm-cases/issue601_xss.text
new file mode 100644
index 00000000..3d584a21
--- /dev/null
+++ b/test/tm-cases/issue601_xss.text
@@ -0,0 +1,1 @@
+<img src=# onerror="alert()"></p>