mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-11-02 11:12:21 +01:00
fix(benchmarks): prevent Markdown inline injection
This commit is contained in:
@@ -1427,6 +1427,10 @@ def _markdown_display_value(value: Any) -> str:
|
|||||||
safe.append(r"\t")
|
safe.append(r"\t")
|
||||||
elif ord(char) < 32 or ord(char) == 127:
|
elif ord(char) < 32 or ord(char) == 127:
|
||||||
safe.append(f"\\x{ord(char):02x}")
|
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"):
|
elif char in ("\u0085", "\u2028", "\u2029"):
|
||||||
safe.append(f"\\u{ord(char):04x}")
|
safe.append(f"\\u{ord(char):04x}")
|
||||||
else:
|
else:
|
||||||
@@ -1436,7 +1440,11 @@ def _markdown_display_value(value: Any) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def _markdown_code(value: Any) -> str:
|
def _markdown_code(value: Any) -> str:
|
||||||
return f"<code>{_markdown_display_value(value)}</code>"
|
# 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"<code>{text}</code>"
|
||||||
|
|
||||||
|
|
||||||
def _markdown_text(value: Any) -> str:
|
def _markdown_text(value: Any) -> str:
|
||||||
|
|||||||
@@ -2698,5 +2698,67 @@ class TestMarkdownReportIntegrity(unittest.TestCase):
|
|||||||
text.encode("utf-8")
|
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) "
|
||||||
|
" "
|
||||||
|
"`fake_code`"
|
||||||
|
)
|
||||||
|
safe = auditor._markdown_code(malicious)
|
||||||
|
self.assertTrue(safe.startswith("<code>"))
|
||||||
|
self.assertTrue(safe.endswith("</code>"))
|
||||||
|
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 = ""
|
||||||
|
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("<code>[VERIFIED](https://example.invalid/track)</code>", summary)
|
||||||
|
self.assertIn("<code></code>", summary)
|
||||||
|
self.assertNotIn("<a ", summary)
|
||||||
|
self.assertNotIn("<img ", summary)
|
||||||
|
self.assertIn("**MISSING**", summary)
|
||||||
|
|
||||||
|
def test_raw_url_email_and_strikethrough_are_not_active_markdown(self):
|
||||||
|
value = "https://example.invalid/track www.example.invalid mail@example.invalid ~~VERIFIED~~"
|
||||||
|
safe = auditor._markdown_code(value)
|
||||||
|
self.assertIn("https://example.invalid/track", safe)
|
||||||
|
self.assertIn("www.example.invalid", safe)
|
||||||
|
self.assertIn("mail@example.invalid", safe)
|
||||||
|
self.assertIn("~~VERIFIED~~", safe)
|
||||||
|
self.assertNotIn("https://", safe)
|
||||||
|
self.assertNotIn("www.example", safe)
|
||||||
|
|
||||||
|
def test_bidi_formatting_controls_cannot_reorder_display(self):
|
||||||
|
for codepoint in (0x061C, 0x200E, 0x200F, 0x202A, 0x202B, 0x202C,
|
||||||
|
0x202D, 0x202E, 0x2066, 0x2067, 0x2068, 0x2069):
|
||||||
|
value = "start" + chr(codepoint) + "finish"
|
||||||
|
escaped = auditor._markdown_display_value(value)
|
||||||
|
self.assertNotIn(chr(codepoint), escaped)
|
||||||
|
self.assertIn(f"\\u{codepoint:04x}", escaped)
|
||||||
|
self.assertIn("finish", escaped)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user