From f9867f3e8b2f5223fbc328f33286b145da541836 Mon Sep 17 00:00:00 2001 From: Alexandre Teixeira Date: Mon, 2 Nov 2026 01:02:14 +0000 Subject: [PATCH] fix(benchmarks): prevent Markdown inline injection --- scripts/audit_c5_benchmark_evidence.py | 10 +++- tests/test_audit_c5_benchmark_evidence.py | 62 +++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/scripts/audit_c5_benchmark_evidence.py b/scripts/audit_c5_benchmark_evidence.py index ee09185f7..38e2740a9 100644 --- a/scripts/audit_c5_benchmark_evidence.py +++ b/scripts/audit_c5_benchmark_evidence.py @@ -1427,6 +1427,10 @@ def _markdown_display_value(value: Any) -> str: safe.append(r"\t") elif ord(char) < 32 or ord(char) == 127: safe.append(f"\\x{ord(char):02x}") + elif (ord(char) in (0x061C, 0x200E, 0x200F) + or 0x202A <= ord(char) <= 0x202E + or 0x2066 <= ord(char) <= 0x2069): + safe.append(f"\\u{ord(char):04x}") elif char in ("\u0085", "\u2028", "\u2029"): safe.append(f"\\u{ord(char):04x}") else: @@ -1436,7 +1440,11 @@ def _markdown_display_value(value: Any) -> str: def _markdown_code(value: Any) -> str: - return f"{_markdown_display_value(value)}" + # Raw HTML code tags do not suppress Markdown inline parsing or autolinks. + text = _markdown_text(value) + for char in (".", ":", "@", "~"): + text = text.replace(char, f"&#{ord(char)};") + return f"{text}" def _markdown_text(value: Any) -> str: diff --git a/tests/test_audit_c5_benchmark_evidence.py b/tests/test_audit_c5_benchmark_evidence.py index 2f70ed117..eb80432a9 100644 --- a/tests/test_audit_c5_benchmark_evidence.py +++ b/tests/test_audit_c5_benchmark_evidence.py @@ -2698,5 +2698,67 @@ class TestMarkdownReportIntegrity(unittest.TestCase): text.encode("utf-8") +# --------------------------------------------------------------------------- +# Markdown inline-safety: raw HTML code tags still parse Markdown syntax. +# --------------------------------------------------------------------------- + +class TestMarkdownInlineSafety(unittest.TestCase): + def test_code_field_escapes_link_image_emphasis_and_backticks(self): + malicious = ( + "[**VERIFIED**](https://example.invalid/track) " + "![beacon](https://example.invalid/beacon.png) " + "`fake_code`" + ) + safe = auditor._markdown_code(malicious) + self.assertTrue(safe.startswith("")) + self.assertTrue(safe.endswith("")) + self.assertIn("[", safe) + self.assertIn("]", safe) + self.assertIn("!", safe) + self.assertIn("*", safe) + self.assertIn("`", safe) + self.assertNotIn("[**VERIFIED**]", safe) + self.assertNotIn("![beacon]", safe) + + def test_report_renders_potential_links_as_literal_syntax(self): + with tempfile.TemporaryDirectory() as td: + root = Path(td) + malicious_path = "[VERIFIED](https://example.invalid/track)" + malicious_campaign = "![beacon](https://example.invalid/collect.png)" + manifest = root / "manifest.json" + manifest.write_text(json.dumps(_manifest( + [{"path": malicious_path, "type": "result_record"}], + campaign_id=malicious_campaign, + ))) + result = auditor.audit(str(manifest), str(root), deterministic=True) + self.assertEqual(result["artifacts"][0]["status"], auditor.MISSING) + summary = auditor._markdown_summary(result) + self.assertIn("[VERIFIED](https://example.invalid/track)", summary) + self.assertIn("![beacon](https://example.invalid/collect.png)", summary) + self.assertNotIn("