From e1b3204c2af639e2a5ccf01d76f3dd280304702e Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 8 Sep 2026 15:19:14 +0200 Subject: test: wire leaky.eml into the anti-leak suite (red, defect 2) test_no_ioc_holds_a_recipient_address grepped for the literal "example.org", and every existing fixture hides the recipient address as base64, so URL redaction could be disabled entirely and both this test and test_cli's counterpart stayed green. leaky.eml carries you@example.org in five URL shapes plus a From display-name trap. Adding it to the fixture list, plus a new test asserting on the raw address and its percent-encoded form, turns the suite red: the valueless-query-parameter defect (redact.py) currently lets ?victim@example.org through as a kept parameter NAME. Left failing on purpose; the next commit fixes redact.py and turns it green. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KphFXTc2QajxXsHWyvGJ4R --- tests/fixtures/leaky.eml | 20 ++++++++++++++++++++ tests/test_parse.py | 10 +++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/leaky.eml (limited to 'tests') diff --git a/tests/fixtures/leaky.eml b/tests/fixtures/leaky.eml new file mode 100644 index 0000000..840ce6d --- /dev/null +++ b/tests/fixtures/leaky.eml @@ -0,0 +1,20 @@ +Received: from mx.example.org (mx.example.org [192.0.2.11]) + by mail.example.org (Postfix) with ESMTP id III99 + for ; Tue, 8 Sep 2026 16:00:02 +0200 (CEST) +Received: from sender.example.invalid (unknown [203.0.113.42]) + by mx.example.org (Postfix) with ESMTP id JJJ11 + for ; Tue, 8 Sep 2026 16:00:01 +0200 (CEST) +Return-Path: +From: "Billing at billing@innocent.example" +To: +Subject: Confirm now +Message-ID: +Date: Tue, 8 Sep 2026 16:00:00 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 + +Plain value: http://a.example.invalid/p?e=you@example.org +Valueless param: http://b.example.invalid/p?you@example.org +In the fragment: http://c.example.invalid/p#e=you@example.org +In userinfo: http://you%40example.org:pw@d.example.invalid/p +Nested redirect: http://t.example.invalid/c?url=http%3A%2F%2Fe.example.invalid%2Fp%3Fe%3Dyou%40example.org diff --git a/tests/test_parse.py b/tests/test_parse.py index 28c8609..a29b7a1 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -213,12 +213,20 @@ class TestIocAssembly(unittest.TestCase): def test_no_ioc_holds_a_recipient_address(self): # The safety property, asserted over the whole output. for name in ("simple.eml", "forged-chain.eml", "with-attachment.eml", - "redirector.eml"): + "redirector.eml", "leaky.eml"): iocs = parse.iocs(load(name), trusted=["192.0.2.0/24"]) blob = repr(iocs) self.assertNotIn("you@example.org", blob) self.assertNotIn("example.org", blob) + def test_the_address_does_not_survive_any_url_shape(self): + # leaky.eml carries you@example.org in five placements. Each one has + # been a real leak in this codebase or is one shape away from it. + iocs = parse.iocs(load("leaky.eml"), trusted=["192.0.2.0/24"]) + blob = repr(iocs) + self.assertNotIn("you@example.org", blob) + self.assertNotIn("you%40example.org", blob) + if __name__ == "__main__": unittest.main() -- cgit v1.2.3