mgmt: v12 implicit creator power is invisible to the link authority check — a v12 creator cannot link their own room #112

Closed
opened 2026-07-12 19:16:43 +00:00 by robocub · 3 comments
Collaborator

Third finding from the #109 fixture's first live runs (fed_link_v12), sibling of #110/#111. After the via-hinted probe join succeeded, link of a remotely-minted v12 room was refused with "you have no individual moderator role there (your power comes from the room's default)" — said to the room's creator.

Mechanism: in room v12 (MSC4289) creators hold implicit infinite power and are FORBIDDEN from appearing in users[] — so evaluate_sender_authority's explicit-grant check (the #86/#79-hardened bar) can structurally never authorize a v12 creator. Every v12 room minted by Element X etc. is unlinkable by its own creator unless someone hands out a redundant explicit grant (which v12 forbids for creators themselves).

Fix (in flight on feat/109-federation-fixture, per operator go): recognize creatorship as room authority — read the create event (v12 room id IS the create event id per MSC4291, so $<hash> is fetchable directly; additional_creators ride the create content) and let joined && creator pass. Fail-closed: any read failure → empty creator set → the explicit-grant path as before. Keeps the #79-finding-6 immunity (creators are unforgeable in the create event; no defaults manipulation mints one). Unit-tested + live-verified: fed_link_v12 now PASSES against the fixture.

**Third finding from the #109 fixture's first live runs (`fed_link_v12`), sibling of #110/#111.** After the via-hinted probe join succeeded, `link` of a remotely-minted v12 room was refused with *"you have no individual moderator role there (your power comes from the room's default)"* — said to the room's **creator**. **Mechanism:** in room v12 (MSC4289) creators hold implicit infinite power and are FORBIDDEN from appearing in `users[]` — so `evaluate_sender_authority`'s explicit-grant check (the #86/#79-hardened bar) can structurally never authorize a v12 creator. Every v12 room minted by Element X etc. is unlinkable by its own creator unless someone hands out a redundant explicit grant (which v12 forbids for creators themselves). **Fix (in flight on `feat/109-federation-fixture`, per operator go):** recognize creatorship as room authority — read the create event (v12 room id IS the create event id per MSC4291, so `$<hash>` is fetchable directly; `additional_creators` ride the create content) and let `joined && creator` pass. Fail-closed: any read failure → empty creator set → the explicit-grant path as before. Keeps the #79-finding-6 immunity (creators are unforgeable in the create event; no defaults manipulation mints one). Unit-tested + live-verified: `fed_link_v12` now PASSES against the fixture.
Author
Collaborator

Fixed in master 172f55f (merged 25138b1). read_room_creators resolves the v12+ creator set — the create event is fetched directly (MSC4291: v12 room id ↔ create event id, so $<hash> is addressable; its sender = first creator) plus additional_creators from the create content — and evaluate_sender_authority now passes joined && creator. Fail-closed: any read failure or pre-v12 room → empty creator set → the existing explicit-grant path unchanged. Keeps the #79-finding-6 immunity (creators are unforgeable in the create event).

Live proof: fed_link_v12 pre-fix was refused with "your power comes from the room's default" said to the room's creator; post-fix it passes (11.1 s — domainless id parse → via-hinted federated probe join → creator authority → pending approval code), re-confirmed in the CI dispatch leg. Unit coverage: sender_authority_recognizes_v12_creators (+13 existing authority tests still green).

✅ **Fixed in master `172f55f`** (merged `25138b1`). `read_room_creators` resolves the v12+ creator set — the create event is fetched directly (MSC4291: v12 room id ↔ create event id, so `$<hash>` is addressable; its `sender` = first creator) plus `additional_creators` from the create content — and `evaluate_sender_authority` now passes `joined && creator`. Fail-closed: any read failure or pre-v12 room → empty creator set → the existing explicit-grant path unchanged. Keeps the #79-finding-6 immunity (creators are unforgeable in the create event). **Live proof:** `fed_link_v12` pre-fix was refused with "your power comes from the room's default" said to the room's creator; post-fix it passes (11.1 s — domainless id parse → via-hinted federated probe join → creator authority → pending approval code), re-confirmed in the CI dispatch leg. Unit coverage: `sender_authority_recognizes_v12_creators` (+13 existing authority tests still green).
Author
Collaborator

Live validation (2026-07-13) — fix confirmed correct against a real user's room; leaving closed.

A self-serve user hit exactly this in the wild: link on their v12 room was refused with "you have no individual moderator role there." Their attempt was on beta.1 — i.e. before this fix shipped (it deployed to prod in v0.3.0-beta.2, ~14 h later), so the failure is expected for that build.

Verified the deployed fix resolves their case against their actual room (reads with the bot's token): the m.room.create state reports room_version: "12", and the create event's sender is the requester — so read_room_creators returns the requester in the creator set and evaluate_sender_authority authorizes them via the creator bypass. read_room_creators is byte-identical in the deployed tag.

Their client also showed a 403 M_FORBIDDEN "Event is not authorized" when they tried to add themselves to m.room.power_levels as a workaround — that is expected v12 behaviour (a server won't place a creator into power_levels; their authority lives in the create event) and is unnecessary once they retry on the current build.

Awaiting their retry to confirm end-to-end; will reopen only if it recurs on beta.2+.

**Live validation (2026-07-13) — fix confirmed correct against a real user's room; leaving closed.** A self-serve user hit exactly this in the wild: `link` on their v12 room was refused with *"you have no individual moderator role there."* Their attempt was on **beta.1** — i.e. before this fix shipped (it deployed to prod in v0.3.0-beta.2, ~14 h later), so the failure is expected for that build. Verified the deployed fix resolves their case against their **actual** room (reads with the bot's token): the `m.room.create` state reports `room_version: "12"`, and the create event's `sender` is the requester — so `read_room_creators` returns the requester in the creator set and `evaluate_sender_authority` authorizes them via the creator bypass. `read_room_creators` is byte-identical in the deployed tag. Their client also showed a `403 M_FORBIDDEN "Event is not authorized"` when they tried to add themselves to `m.room.power_levels` as a workaround — that is expected v12 behaviour (a server won't place a creator into `power_levels`; their authority lives in the create event) and is unnecessary once they retry on the current build. Awaiting their retry to confirm end-to-end; will reopen only if it recurs on beta.2+.
Author
Collaborator

Confirmed end-to-end in prod (2026-07-13). The reporter retried link on his v12 room against v0.3.0-beta.2 and it succeeded — now bridged and joined a call. The earlier failure was purely the beta.1 build predating this fix.

**Confirmed end-to-end in prod (2026-07-13).** The reporter retried `link` on his v12 room against v0.3.0-beta.2 and it **succeeded** — now bridged and joined a call. The earlier failure was purely the beta.1 build predating this fix.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dark/nether-voicebridge#112
No description provided.