From c8b70a06f6e3d73681ea332ea7cdf5e5dd228172 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 1 May 2026 05:05:59 +0000 Subject: [PATCH] fix(core): escape Telegram HTML output Co-authored-by: Bayashat --- src/bot/services/ai/telegram_html.py | 3 ++- tests/test_telegram_html.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/bot/services/ai/telegram_html.py b/src/bot/services/ai/telegram_html.py index ed0f0e8..e384a57 100644 --- a/src/bot/services/ai/telegram_html.py +++ b/src/bot/services/ai/telegram_html.py @@ -2,6 +2,7 @@ from __future__ import annotations +from html import escape import re _BOLD_RE = re.compile(r"\*\*(.+?)\*\*") @@ -15,7 +16,7 @@ def normalize_llm_output_for_telegram_html(text: str) -> str: lines = text.splitlines() normalized_lines: list[str] = [] for line in lines: - normalized_lines.append(_BULLET_RE.sub("• ", line)) + normalized_lines.append(_BULLET_RE.sub("• ", escape(line, quote=False))) normalized = "\n".join(normalized_lines) normalized = _BOLD_RE.sub(r"\1", normalized) diff --git a/tests/test_telegram_html.py b/tests/test_telegram_html.py index 2c8b4ed..b44856f 100644 --- a/tests/test_telegram_html.py +++ b/tests/test_telegram_html.py @@ -13,3 +13,15 @@ def test_markdown_bullets_to_dot_bullets() -> None: text = "- first\n* second\n - third" out = normalize_llm_output_for_telegram_html(text) assert out.splitlines() == ["• first", "• second", "• third"] + + +def test_escapes_raw_html_control_characters() -> None: + text = "Use x < y && y > 0 in ." + out = normalize_llm_output_for_telegram_html(text) + assert out == "Use x < y && y > 0 in <script>alert(1)</script>." + + +def test_markdown_formatting_escapes_inner_html() -> None: + text = "**x < y** and `a & b`" + out = normalize_llm_output_for_telegram_html(text) + assert out == "x < y and a & b"