From c50bbb6d9271f626db85207bf5e049935f46aa9c Mon Sep 17 00:00:00 2001
From: Abhijith A
Date: Sun, 18 Oct 2026 22:41:02 +0530
Subject: [PATCH] Fix XSS in safe_mode via image tags missing _safe_href check
Image tags () in safe_mode do not validate the URL against
_safe_href, unlike anchor tags which do. This allows javascript:,
vbscript:, and other dangerous URL schemes through in
attributes when safe_mode is enabled.
Apply the same _safe_href check used for anchors to image src URLs,
replacing the URL with an empty string when it fails validation.
Co-Authored-By: Claude Opus 4.6
---
lib/markdown2.py | 2 ++
test/tm-cases/img_safe_mode_xss.html | 9 +++++++++
test/tm-cases/img_safe_mode_xss.opts | 1 +
test/tm-cases/img_safe_mode_xss.text | 9 +++++++++
4 files changed, 21 insertions(+)
create mode 100644 test/tm-cases/img_safe_mode_xss.html
create mode 100644 test/tm-cases/img_safe_mode_xss.opts
create mode 100644 test/tm-cases/img_safe_mode_xss.text
diff --git a/lib/markdown2.py b/lib/markdown2.py
index 66d49a69..6c18f3bb 100755
--- a/lib/markdown2.py
+++ b/lib/markdown2.py
@@ -3229,6 +3229,8 @@ def process_image(self, url: str, title_attr: str, link_text: str) -> Tuple[str,
This section will be skipped by the link processor
'''
img_class_str = self.md._html_class_str_from_tag("img")
+ if self.md.safe_mode and not self.md._safe_href.match(url):
+ url = ''
result = (
f'})
![xss]()
+
+![xss]()
+
+![xss]()
+
+
+
+
diff --git a/test/tm-cases/img_safe_mode_xss.opts b/test/tm-cases/img_safe_mode_xss.opts
new file mode 100644
index 00000000..ad487c04
--- /dev/null
+++ b/test/tm-cases/img_safe_mode_xss.opts
@@ -0,0 +1 @@
+{"safe_mode": "escape"}
diff --git a/test/tm-cases/img_safe_mode_xss.text b/test/tm-cases/img_safe_mode_xss.text
new file mode 100644
index 00000000..a13a1fa7
--- /dev/null
+++ b/test/tm-cases/img_safe_mode_xss.text
@@ -0,0 +1,9 @@
+)
+
+)
+
+)
+
+
+
+