mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-04 13:28:04 +00:00
An `m.room.member` event's `content.localpart` and `content.domain` claim who the member key in `state_key` belongs to, and the server named by `content.domain` signs the event to vouch for the claim. That signature is not enough on its own: a moderator kicking or banning a member can name a domain they control, vouch for the claim with that domain's signing key, and produce a verifiable but false statement about somebody else — defacing an innocent member with an abusive localpart, or pointing them at a server that then receives their traffic. So require the claim to come from the member too. The member key named by `state_key` signs the event under the entity `state_key`, with the member keys' constant key ID, and linkage information on an event the member did not send is ignored unless it is there. A moderator cannot produce that signature without the member's key, and the absence of one costs them nothing: the kick or the ban still takes effect, since this is not a validity rule. It only decides whether anyone believes what the event says about who was kicked. The events this server builds follow suit. A membership event sent by one of our users about another — an invite — now carries the target's own signature alongside ours, which is what makes it worth anything to the servers that receive it. A kick, a ban or an unban carries no linkage information at all: we would be asserting something we are not entitled to assert, and the target's localpart has no business being published on somebody else's event. Members' own events are unchanged; their `sender` signature is already their assertion, and a second copy of it would say nothing more. This replaces the previous arrangement, where the server's signature vouching for linkage information was made under the constant `state_key` rather than under the server's own name. That distinguished a claim about the target from one about the sender, but it did not establish who was entitled to make it. The entity name goes back to the server's name, as everywhere else in Matrix, and `state_key` now names what it says: the member key in the event's state key, signing for itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>