Matrix: moho misreads its own power in a v12 room #134

Closed
opened 2026-09-06 22:46:57 -04:00 by Salastil · 1 comment
Owner

In room version 12 the creator's power is implicit in m.room.create and the users map is empty. moho computes what this account may do from users alone, so in a room it created itself it believes it has power 0:

setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)"

while the server accepts the same change from the same account without complaint. So moderation actions moho could perform are refused by moho before the server ever sees them — in exactly the rooms the account owns.

What it needs: read the creator from m.room.create (and, for v12+, treat the creator as above everybody), rather than defaulting to users_default when the users map has no entry. The same reading feeds the gates on the message and member menus, so those are wrong in the same rooms.

Found while testing Element interop: the room had been created by the account that could not, apparently, moderate it.

In room version 12 the creator's power is implicit in `m.room.create` and the `users` map is empty. moho computes what this account may do from `users` alone, so in a room it created itself it believes it has power 0: ``` setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)" ``` while the server accepts the same change from the same account without complaint. So moderation actions moho *could* perform are refused by moho before the server ever sees them — in exactly the rooms the account owns. **What it needs:** read the creator from `m.room.create` (and, for v12+, treat the creator as above everybody), rather than defaulting to `users_default` when the `users` map has no entry. The same reading feeds the gates on the message and member menus, so those are wrong in the same rooms. Found while testing Element interop: the room had been created by the account that could not, apparently, moderate it.
Salastil added the bug label 2026-09-06 22:46:57 -04:00
Author
Owner

Finished — https://git.salastil.com/Salastil/nobilis/commit/f027f53 and https://git.salastil.com/Salastil/moho/commit/99e4858

Power is read as the room actually grants it now: the creators named in m.room.create — its sender, plus version 12's additional_creators — outrank every number where the room version says they do.

Nothing changes for older rooms, deliberately. Before version 12 a creator is simply whoever holds 100 and can be demoted like anybody else, so an empty users map there really does mean the room has no admin left. Inventing an owner would be the same bug in the other direction.

Both shapes of the create event are read. A sync carries the whole event, sender included; asking the server for one piece of state returns the content alone, which has no sender — and the sender is exactly who made a v12 room. So the sync's copy is preferred and the fetch is the fallback. Getting this backwards is why the first attempt at the fix still failed.

Verified against the room that produced the bug (v12, created by @salastil:poa.st, empty users):

before  setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)"
after   setMatrixPowerLevel → granted moderator, then took it back again
        getMatrixRoomPermissions → canKick / canBan / canMute / canRedactOthers all true

Those permissions are what the message and member menus read, so the actions the owner was being denied are offered again. A profile in such a room now says "Owner" rather than printing a power level larger than any room could name.

441 tests pass, five of them new and covering the rule from both sides.

Finished — https://git.salastil.com/Salastil/nobilis/commit/f027f53 and https://git.salastil.com/Salastil/moho/commit/99e4858 Power is read as the room actually grants it now: the creators named in `m.room.create` — its sender, plus version 12's `additional_creators` — outrank every number where the room version says they do. **Nothing changes for older rooms**, deliberately. Before version 12 a creator is simply whoever holds 100 and can be demoted like anybody else, so an empty `users` map there really does mean the room has no admin left. Inventing an owner would be the same bug in the other direction. **Both shapes of the create event are read.** A sync carries the whole event, sender included; asking the server for one piece of state returns the *content* alone, which has no sender — and the sender is exactly who made a v12 room. So the sync's copy is preferred and the fetch is the fallback. Getting this backwards is why the first attempt at the fix still failed. **Verified against the room that produced the bug** (v12, created by `@salastil:poa.st`, empty `users`): ``` before setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)" after setMatrixPowerLevel → granted moderator, then took it back again getMatrixRoomPermissions → canKick / canBan / canMute / canRedactOthers all true ``` Those permissions are what the message and member menus read, so the actions the owner was being denied are offered again. A profile in such a room now says "Owner" rather than printing a power level larger than any room could name. 441 tests pass, five of them new and covering the rule from both sides.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Salastil/moho#134