mgmt: v12 implicit creator power is invisible to the link authority check — a v12 creator cannot link their own room #112
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
dark/nether-voicebridge#112
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Third finding from the #109 fixture's first live runs (
fed_link_v12), sibling of #110/#111. After the via-hinted probe join succeeded,linkof 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[]— soevaluate_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_creatorsride the create content) and letjoined && creatorpass. 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_v12now PASSES against the fixture.✅ Fixed in master
172f55f(merged25138b1).read_room_creatorsresolves the v12+ creator set — the create event is fetched directly (MSC4291: v12 room id ↔ create event id, so$<hash>is addressable; itssender= first creator) plusadditional_creatorsfrom the create content — andevaluate_sender_authoritynow passesjoined && 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_v12pre-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).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:
linkon 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.createstate reportsroom_version: "12", and the create event'ssenderis the requester — soread_room_creatorsreturns the requester in the creator set andevaluate_sender_authorityauthorizes them via the creator bypass.read_room_creatorsis byte-identical in the deployed tag.Their client also showed a
403 M_FORBIDDEN "Event is not authorized"when they tried to add themselves tom.room.power_levelsas a workaround — that is expected v12 behaviour (a server won't place a creator intopower_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+.
Confirmed end-to-end in prod (2026-07-13). The reporter retried
linkon 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.