From fd8339703ccb99fccb95059996001f6734043655 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 8 Sep 2026 16:28:01 +0200 Subject: fix: take the sender domain from the address, not the display name _ADDR_DOMAIN.search() returned the first @domain anywhere in the raw header text. A display name sits before the angle brackets and is attacker-controlled, so it won. Two ways that reached a published report. The sender was misattributed: "Billing at billing@innocent.example" filed the report against a third party who sent nothing. And it defeated the structural guarantee in sender_domains(): the module reads no recipient header, but an attacker who writes the victim's own address into the display name hands it one anyway, and it came back out as a sender domain. parseaddr() parses the header grammar rather than scanning it, so a quoted display name cannot supply the address. leaky.eml's display name now carries the recipient address. The existing test_no_ioc_holds_a_recipient_address assertion catches this class; it was green before only because the fixture used a harmless domain. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019NHaqA1Rz5ybed7wFUeQbK --- tests/fixtures/leaky.eml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/fixtures/leaky.eml') diff --git a/tests/fixtures/leaky.eml b/tests/fixtures/leaky.eml index 840ce6d..f98d191 100644 --- a/tests/fixtures/leaky.eml +++ b/tests/fixtures/leaky.eml @@ -5,7 +5,7 @@ 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" +From: "Billing at you@example.org" To: Subject: Confirm now Message-ID: -- cgit v1.2.3