diff --git a/changedetectionio/tests/smtp/test_notification_smtp.py b/changedetectionio/tests/smtp/test_notification_smtp.py
index ec646c8c..a163c6f6 100644
--- a/changedetectionio/tests/smtp/test_notification_smtp.py
+++ b/changedetectionio/tests/smtp/test_notification_smtp.py
@@ -108,7 +108,9 @@ def test_check_notification_email_formats_default_HTML(client, live_server, meas
html_content = html_part.get_content()
assert 'some text
' in html_content # We converted \n from the notification body
assert 'fallback-body
' in html_content # kept the original
- assert '(added) So let\'s see what happens.
' in html_content # the html part
+ # GHSA-q8xq-qg4x-wphg: apostrophes in diff content are escaped (') for HTML notifications.
+ # Renders as ' in the recipient's email client; only the byte-source differs.
+ assert '(added) So let's see what happens.
' in html_content # the html part
delete_all_watches(client)
@@ -452,7 +454,8 @@ def test_check_notification_email_formats_default_Text_override_HTML(client, liv
html_part = parts[1]
assert html_part.get_content_type() == 'text/html'
html_content = html_part.get_content()
- assert '(removed) So let\'s see what happens.' in html_content # the html part
+ # GHSA-q8xq-qg4x-wphg: apostrophes in diff content are escaped (') for HTML notifications.
+ assert '(removed) So let's see what happens.' in html_content # the html part
assert '<!DOCTYPE html' not in html_content
assert '' in html_content # We converted \n from the notification body
assert 'fallback-body
' in html_content # kept the original
- assert '(added) So let\'s see what happens.
' in html_content # the html part
+ # GHSA-q8xq-qg4x-wphg: apostrophes in diff content are escaped (') for HTML notifications.
+ assert '(added) So let's see what happens.
' in html_content # the html part
delete_all_watches(client)
\ No newline at end of file
diff --git a/changedetectionio/tests/test_notification.py b/changedetectionio/tests/test_notification.py
index 1d666793..04765165 100644
--- a/changedetectionio/tests/test_notification.py
+++ b/changedetectionio/tests/test_notification.py
@@ -790,3 +790,79 @@ def test_html_watch_diff_content_escaped_in_html_notification(client, live_serve
f"Diff content from text/html page was NOT escaped — tracking pixel reached HTML notification: {body!r}"
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
+
+
+def test_source_url_diff_content_escaped_in_html_notification(client, live_server, measure_memory_usage, datastore_path):
+ """
+ GHSA-q8xq-qg4x-wphg — companion to the inscriptis test. `source:`-prefixed
+ URLs short-circuit the HTML→text step (processor.py:509-511) and store the
+ raw HTML body verbatim as the snapshot. That gives an attacker who controls
+ a watched page a *direct* injection path — no entity-encoding tricks needed,
+ any live `` / `
` / `