From 6305ef216de6e76f2aeeb1c240fabd05255e298b Mon Sep 17 00:00:00 2001 From: beduldul Date: Sun, 25 Oct 2026 18:37:50 +0700 Subject: [PATCH] Escape the language in hpre so it can't break the class attribute hpre() inserts language straight into the class attribute while escaping content. A quote in the language ends the attribute early: >>> hpre("x", language='a"b') '
x
' Telegram rejects that as malformed HTML, and a crafted language adds attributes instead: hpre("x", language='a" onmouseover="alert(1)') parses as class="a" onmouseover="alert(1)". Run language through escape_html() the same way content already is. Plain values are unchanged, since html.escape() only touches & < > " '. --- telebot/formatting.py | 2 +- tests/test_formatting.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/test_formatting.py diff --git a/telebot/formatting.py b/telebot/formatting.py index 871c293b4..73f737fd4 100644 --- a/telebot/formatting.py +++ b/telebot/formatting.py @@ -312,7 +312,7 @@ def hpre(content: str, escape: Optional[bool]=True, language: str="") -> str: :return: The formatted string. :rtype: :obj:`str` """ - return '
{}
'.format(language, escape_html(content) if escape else content) + return '
{}
'.format(escape_html(language), escape_html(content) if escape else content) def hide_link(url: str) -> str: diff --git a/tests/test_formatting.py b/tests/test_formatting.py new file mode 100644 index 000000000..eb0eabdfb --- /dev/null +++ b/tests/test_formatting.py @@ -0,0 +1,37 @@ +import sys + +sys.path.append('../') + +from html.parser import HTMLParser + +from telebot.formatting import hpre + + +class AttributeCollector(HTMLParser): + def __init__(self): + super().__init__() + self.tags = [] + + def handle_starttag(self, tag, attrs): + self.tags.append((tag, attrs)) + + +def test_hpre_keeps_plain_language(): + assert hpre("x", language="python") == '
x
' + + +def test_hpre_escapes_quotes_in_language(): + assert hpre("x", language='a"b') == '
x
' + + +def test_hpre_language_cannot_add_attributes(): + parser = AttributeCollector() + parser.feed(hpre("x", language='a" onmouseover="alert(1)')) + assert parser.tags == [ + ("pre", []), + ("code", [("class", 'a" onmouseover="alert(1)')]), + ] + + +def test_hpre_still_escapes_content(): + assert hpre("", language="python") == '
<b>
'