From 8c3a479eeef7d19c976b5979ca25a1e3f2c70dbe Mon Sep 17 00:00:00 2001 From: Swastik Tripathi Date: Sat, 14 Nov 2026 08:55:22 +0530 Subject: [PATCH 1/2] Unescape backslash-escaped quotes in link and image titles --- lib/markdown2.py | 3 +++ test/tm-cases/link_title_escaped_quotes.html | 7 +++++++ test/tm-cases/link_title_escaped_quotes.text | 9 +++++++++ 3 files changed, 19 insertions(+) create mode 100644 test/tm-cases/link_title_escaped_quotes.html create mode 100644 test/tm-cases/link_title_escaped_quotes.text diff --git a/lib/markdown2.py b/lib/markdown2.py index d6285404..e2a61bce 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -3423,6 +3423,9 @@ def run(self, text: str): if self.md.safe_mode: # expose span contents for escaping - fix #691, #703 title = self.md._unhash_html_spans(title, spans=True, code=True) + # A backslash-escaped quote is just a quote. Left in, `\"` becomes `\"`, which the + # escaped-ampersand handling then turns into a literal `"` in the title. + title = title.replace('\\"', '"').replace("\\'", "'") title = ( _xml_escape_attr(title) .replace('*', self.md._escape_table['*']) diff --git a/test/tm-cases/link_title_escaped_quotes.html b/test/tm-cases/link_title_escaped_quotes.html new file mode 100644 index 00000000..bffa9c2f --- /dev/null +++ b/test/tm-cases/link_title_escaped_quotes.html @@ -0,0 +1,7 @@ +

Inline

+ +

Single

+ +

Reference

+ +

Image

diff --git a/test/tm-cases/link_title_escaped_quotes.text b/test/tm-cases/link_title_escaped_quotes.text new file mode 100644 index 00000000..e82ecf88 --- /dev/null +++ b/test/tm-cases/link_title_escaped_quotes.text @@ -0,0 +1,9 @@ +[Inline](http://example.com "Say \"hi\"") + +[Single](http://example.com 'It\'s here') + +[Reference][ref] + +![Image](a.png "A \"quoted\" title") + +[ref]: http://example.com "Say \"hi\"" From 94e11ecd5e9e67a7da442dcf7b60ba1193139732 Mon Sep 17 00:00:00 2001 From: Swastik Tripathi Date: Sat, 14 Nov 2026 08:55:35 +0530 Subject: [PATCH 2/2] Add changelog entry for #778 --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 10aabd33..82c57fc1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## python-markdown2 2.5.6 (not yet released) +- [pull #778] Fix backslash-escaped quotes in link and image titles being rendered as a literal `"` - [pull #762] Speed up documents with many links by skipping the backslash-escape scan for text without a backslash - [pull #748] Speed up `_unescape_special_chars` by skipping text with no hashes and dropping the full-text comparison per pass (#635) - [pull #749] URL-encode destinations generated by the `link-patterns` extra (#55)