mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-11-09 10:51:44 +00:00
Neutralize CSV formulas and escape control characters in logged strings (#931)
* Neutralize CSV formulas and escape control characters in logged strings CSV fields starting with =, +, -, @, tab, or CR get a leading apostrophe (OWASP CSV Injection, CWE-1236). Sender-controlled subject/From and a few aggregate-parser values are passed through the new sanitize_for_log() before they reach error messages and logs. Closes #929 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Sanitize more sender-controlled log values; fix sanitize_for_log docs Escape the SMTP TLS policy-type in its error and org_name/report_id in the duplicate-report debug lines, correct the sanitize_for_log docstring, and drop the unreachable return in parse_report_email(). Closes #929 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Test the From-header escaping with a raw control character mail-parser 4.8.0, which CI resolves, no longer decodes an RFC 2047 encoded word in the From header (4.6.2 did), so the previous test saw the encoded word rather than the CR LF it was meant to observe. A raw ESC in the display name survives both versions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
c1e7662e9e
commit
16a9016e2a
7 files changed
+284
-30
No files matched your search
@@ -471,6 +471,31 @@ class Test(unittest.TestCase):
|
||||
self.assertTrue(parsedmarc.utils.is_outlook_msg(magic))
|
||||
|
||||
|
||||
class TestSanitizeForLog(unittest.TestCase):
|
||||
"""Tests for parsedmarc.utils.sanitize_for_log()"""
|
||||
|
||||
def testEscapesNonPrintableAndKeepsPrintable(self):
|
||||
cases = [
|
||||
("plain ASCII", "plain ASCII"),
|
||||
("", ""),
|
||||
("line1\r\nINJECTED fake log", "line1\\r\\nINJECTED fake log"),
|
||||
("a\tb", "a\\tb"),
|
||||
("\x1b[31mred", "\\x1b[31mred"),
|
||||
("a\u2028b", "a\\u2028b"),
|
||||
("nul\x00byte", "nul\\x00byte"),
|
||||
("\u65e5\u672c\u8a9e report", "\u65e5\u672c\u8a9e report"),
|
||||
("ok \U0001f600", "ok \U0001f600"),
|
||||
]
|
||||
for value, expected in cases:
|
||||
with self.subTest(value=value):
|
||||
self.assertEqual(parsedmarc.utils.sanitize_for_log(value), expected)
|
||||
|
||||
def testResultHasNoRawControlCharacters(self):
|
||||
result = parsedmarc.utils.sanitize_for_log("a\r\nb\nc\rd")
|
||||
self.assertNotIn("\r", result)
|
||||
self.assertNotIn("\n", result)
|
||||
|
||||
|
||||
class TestLoadPSLOverrides(unittest.TestCase):
|
||||
"""Covers `parsedmarc.utils.load_psl_overrides`."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user