From 610b689a7dd6b2f9ac1879a24b7b87c4a52e30ea Mon Sep 17 00:00:00 2001 From: Mark Mennell Date: Thu, 29 Oct 2026 18:20:37 +0800 Subject: [PATCH] Add-to: a stored original's participants decide who may add recipients The stored-parent add-to steps checked terminal and time travel but not that add to from is a participant of the stored original. The only check listed (step 1) is against the incoming header's own from and to, which the sender writes, so an outsider could name themselves there and have a stored message attached to an address of their choosing. NOTE I and section 12 already require add to from to be an original participant; this makes the receiving steps check it against the stored message. Co-Authored-By: Claude Opus 5.5 --- SPEC.md | 2 +- SPECIFICATION.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SPEC.md b/SPEC.md index d35fcb9..b262fdc 100644 --- a/SPEC.md +++ b/SPEC.md @@ -225,7 +225,7 @@ When _has add to_ IS set: perform the steps below for each unique participant do - **add-to set** (adding recipients): - pid MUST also be set. Fail → respond code 1, close. - Check if parent stored (§11): - - **Stored**: parent must not be terminal (code 1 if fail); check time travel (code 9 if fail). + - **Stored**: parent must not be terminal (code 1 if fail); check time travel (code 9 if fail); _add to from_ must be in the stored parent's _from_ or _to_ (code 1 if fail). The incoming header's _from_ and _to_ are not evidence of this: the sender wrote them. - **Not stored**: if ≥ 1 recipient in _to_ or _add to_ belongs to Host B's domain, treat as full message delivery. Otherwise (Host B hosts only non-recipient participants) respond code 6 (parent not found), close. 8. Optionally issue a CHALLENGE on Connection 2 (see §10.5). diff --git a/SPECIFICATION.md b/SPECIFICATION.md index 26a8f83..8b89ad4 100644 --- a/SPECIFICATION.md +++ b/SPECIFICATION.md @@ -535,6 +535,7 @@ The following variables corresponding to host defined configuration are used in 3. If original message referred to by _pid_ is verified to be stored AND; 1. The stored message MUST NOT have the _terminal_ flag bit set; otherwise Host B MUST respond with REJECT code 1 (invalid) completing the message exchange. 2. The stored message for _pid_'s _time_ minus MAX_TIME_SKEW MUST be before _time_ on the incoming message header; otherwise Host B MUST respond with REJECT code 9 (time travel). + 3. _add to from_ MUST be in the stored message's _from_ or _to_; otherwise Host B MUST respond with REJECT code 1 (invalid) completing the message exchange. The incoming header's own _from_ and _to_ (checked in step 1) are written by the sender, so only the stored message shows who its participants are; a recipient added by an earlier batch is a participant of that batch, not of the original. 4. Otherwise (original message has not been found, possible because Host B was never a participant of the message, or the message referenced by _pid_ is no longer held): 1. If at least one recipient in _to_ or _add to_ belongs to Host B, the message is treated as a full message delivery. 2. Otherwise Host B hosts only non-recipient participants of the message; Host B MUST respond REJECT code 6 (parent not found) then close the connection completing the message exchange.