Skip to content
Merged
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions proposals/4311-stripped-state-create-event.md
Copy link
Member Author

@turt2live turt2live Jul 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation requirements:

  • Server (returning stripped state)
  • Server (receiving stripped state) - See comment below
  • Client (receiving stripped state)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meowlnir (client/bot replacing room ID parsing with creator parsing in invite antispam): maunium/meowlnir@eeccd4a

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though servers haven't actually added the validation on the stripped state yet, per the migration section of the MSC, no one has indicated that it's a nightmare to do so. I'm inclined to consider that "implementation" for the purposes of starting FCP, but welcome (particularly SCT) opinions on whether that's valid.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This MSC now requires all stripped state events to be PDUs over federation. I believe element-hq/synapse#18822 and matrix-org/complement#796 demonstrate it's not impossible, even if the code itself is bad.

Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# MSC4311: Ensuring the create event is available on invites and knocks

Historically, when processing an invite or knock, safety tooling would parse the room ID despite
[being opaque](https://spec.matrix.org/v1.15/appendices/#room-ids) to determine the server which
originally created the room. If that server was considered abusive, the incoming invite or outbound
knock may be rejected or blocked early by the tooling. This approach is preferred because the user
sending the invite may not be on the same server as the user who created the room, though both sender
and creator are checked by safety tooling.

With [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291), room IDs lose their
domain component. This, combined with [Stripped State](https://spec.matrix.org/v1.15/client-server-api/#stripped-state)
recommending rather than requiring the `m.room.create` event, makes the above check harder if not
impossible when the create event is missing or incomplete, as the room ID cannot be confirmed in
MSC4291+ room versions.

This MSC shifts the `m.room.create` event to a *required* stripped state event, and imposes validation
to ensure the event matches the room. To support the new validation, the `m.room.create` event must
be formatted as a full PDU in the stripped state of [invites](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1inviteroomideventid)
over federation. Similar treatment is applied to other stripped state events for uniformity.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar treatment is applied to other stripped state events for uniformity.

But why, aside from vdh's general ick feeling of having 2 data types in the same array? By doing it for all events:

  • we add more bandwidth to invites
  • we don't gain any more security as the events can't be verified via their auth chains
  • we risk giving the impression that we are authorising all events in invite_room_state, which we ain't.

To fix the ick, I'd rather we moved the create event to be a new key outside of invite_room_state and leave invite_room_state as-is, although that would either be backwards incompatible (the create event would be missing from invite_room_state) or duplicate the create event fields if we keep the create event in invite_room_state for a while.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference: this follows on from two previous threads (1, 2) where this was discussed in detail.

we add more bandwidth to invites

This feels negligible though.

we don't gain any more security as the events can't be verified via their auth chains

It is not proposed as a security improvement; rather as one that makes the API more consistent.

we risk giving the impression that we are authorising all events in invite_room_state, which we ain't.

I really don't buy this argument. The fact that an event is passed over the federation API doesn't say anything to me about whether it is authorised or not.

I'll also re-emphasise that if you stick to the "full PDUs make people think that they are authorised" argument, then we have to do something different here for pre-v12 rooms (see previous thread) which is also gnarly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This [additional bandwidth] feels negligible though.

To you perhaps, but this is the main reason why we have the concept of stripped state events at all vs sending full-fat PDUs.

I don't feel strongly on this. Having stripped state always be the full-fat PDU seems fine.


[Knocks](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1send_knockroomideventid)
additionally include the full PDU format, though only to ensure symmetry between the two instances of
stripped state. It's not possible to prevent a knock based on stripped state because the server will
have already sent the knock before stripped state is received.


## Proposal

On the Client-Server API, `m.room.create` MUST be provided in [Stripped State](https://spec.matrix.org/v1.15/client-server-api/#stripped-state),
where available. No other changes are proposed to the Client-Server API. For clarity, this means clients
continue to receive events which only have `content`, `sender`, `state_key` (optional), and `type` in
the `invite_room_state`, `knock_room_state`, and whereever else stripped state is used.

Over federation, servers MUST include the `m.room.create` event in the [`invite_room_state`](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1inviteroomideventid)
and [`knock_room_state`](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1send_knockroomideventid).
Servers MUST additionally format events in `invite_room_state` and `knock_room_state` as PDUs according
to that room version's event format specification. Together, these changes allow servers to validate
the room ID matches the invite (or knock, though it's already sent by the time validation would happen).

Specifically, including the `m.room.create` event as a full PDU allows servers to calculate the room
ID by hashing the event in MSC4291+ room versions. For other room versions (1 through 11), the server
can at most compare the `room_id` field of the create event with the invite/knock membership event.

If any of the events are not a PDU, not for the room ID specified, or fail [signature checks](https://spec.matrix.org/v1.15/server-server-api/#validating-hashes-and-signatures-on-received-events),
or the `m.room.create` event is missing, the receiving server MUST respond to invites with a `400 M_MISSING_PARAM`
standard Matrix error (new to the endpoint). For knocks, the server SHOULD remove any events from
`knock_room_state` which fail the same validation check before passing the details along to clients.
Ideally, the server would be able to prevent the knock from happening, though by the time the server
can see the `knock_room_state`, the knock has already happened.

The `400 M_MISSING_PARAM` error SHOULD be translated to a 5xx error by the sending server over the
Client-Server API. This is done because there's nothing the client can materially do differently to
make the request succeed.

When comparing the room IDs, servers will need to calculate the room ID from the `m.room.create` event
as described by MSC4291 (take the reference hash of the event for an event ID, swap the sigil).


## Potential issues

* Some server implementations allow safety tooling and other applications to hook into them between
the Federation API and Client-Server API. Such implementations are encouraged to make the create
event reasonably available in its full form to those applications. Typically, this will be an internal
representation of the event which still has the capability to serialize down to a PDU.

* Implementations should take care to not unintentionally trust the events contained in `invite_room_state`
and `knock_room_state`, despite appearing as complete events. This is due to the lack of each event's
auth chain being included, and reassurance that the events are the current events.

## Alternatives

This proposal fills a potential gap in information created by MSC4291, making the alternatives roughly
equivalent to "don't do this". A possible alternative is in the shape of [MSC4329](https://github.com/matrix-org/matrix-spec-proposals/pull/4329)
where the `/invite` endpoint changes, however the changes are roughly the same as this proposal's.


## Security considerations

Security considerations are made throughout, especially around validating the events included.


## Unstable prefix

This proposal does not require an unstable prefix as the behaviour can be accomplished without overly
affecting client or server implementations.


## Migration

*This section is for server implementations to follow upon release of room version 12. It is not
intended to enter the spec in any way.*

Room version 12 contains MSC4291 and is expected to be used in production prior to this proposal
becoming stable itself. To account for this, for 1 spec release cycle, servers are encouraged to
warn rather than fail on invites which don't have a complete `m.room.create` PDU in the `invite_room_state`.
If the PDU is complete, but for a different room, the invite should still fail per the proposal text
above.

This translates to a timeline anywhere between 2 and 6 months, depending on ecosystem rollout. An
example *possible* release schedule is:

1. August 2025 - Matrix 1.16 is released with Room Version 12 and this proposal; servers log warnings
about invites missing complete `m.room.create` PDUs.
2. October 2025 - Matrix 1.17 is released; servers stop using warnings and instead fully apply the
validation logic of this proposal, causing invites missing full create event PDUs to fail.

Servers are encouraged to make the switch to full validation early if their ecosystem conditions
allow. For example, if logged warnings are sufficiently low or of insignicant consequence.


## Dependencies

This proposal requires [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291) in
order to make any amount of sense.
Loading