CVE-2022-36009: Incorrect Authorization (CWE-863)
value: gomatrixserverlib is a Go library for matrix protocol federation. Dendrite is a Matrix homeserver written in Go, an alternative to Synapse. The power level parsing within gomatrixserverlib was failing to parse the `"events_default"` key of the `m.room.power_levels` event, defaulting the event default power level to zero in all cases. Power levels are the matrix terminology for user access level. In rooms where the `"events_default"` power level had been changed, this could result in events either being incorrectly authorised or rejected by Dendrite servers. gomatrixserverlib contains a fix as of commit `723fd49` and Dendrite 0.9.3 has been updated accordingly. Matrix rooms where the `"events_default"` power level has not been changed from the default of zero are not vulnerable. Users are advised to upgrade. There are no known workarounds for this issue.
CWE description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
CVSS v3 base score: 8.8
Published: 2022-08-19T21:15Z
Repository: https://github.com/matrix-org/gomatrixserverlib
Language: Go
Files changed: eventauth_test.go, eventcontent.go
Commit date: 2022-08-15 10:19:47 +0100
Commit message: Fix parsing of `"events_default"` level in `m.room.power_levels` events

Diff: diff --git a/eventauth_test.go b/eventauth_test.go
index baf8d77..63532d3 100644
--- a/eventauth_test.go
+++ b/eventauth_test.go
@@ -1135,5 +1135,64 @@ func newMemberContent(
 	return MemberContent{
 		Membership:       membership,
 		ThirdPartyInvite: thirdPartyInvite,
 	}
 }
+
+var negativePowerLevelTestRoom = &testAuthEvents{
+	CreateJSON: json.RawMessage(`{
+		"type": "m.room.create",
+		"state_key": "",
+		"sender": "@u1:a",
+		"room_id": "!r1:a",
+		"event_id": "$e1:a",
+		"content": {
+			"room_version": "10"
+		}
+	}`),
+	PowerLevelsJSON: json.RawMessage(`{
+		"type": "m.room.power_levels",
+		"state_key": "",
+		"sender": "@u1:a",
+		"room_id": "!r1:a",
+		"event_id": "$e3:a",
+		"content": {
+			"events_default": -9007199254740990,
+			"state_default": -9007199254740990,
+			"users_default": -9007199254740990,
+			"users": {
+			}
+		}
+	}`),
+	MemberJSON: map[string]json.RawMessage{
+		"@u1:a": json.RawMessage(`{
+			"type": "m.room.member",
+			"state_key": "@u1:a",
+			"sender": "@u1:a",
+			"room_id": "!r1:a",
+			"event_id": "$e2:a",
+			"content": {
+				"membership": "join"
+			}
+		}`),
+	},
+}
+
+func TestNegativePowerLevels(t *testing.T) {
+	// User should be able to demote the user default level
+	// below their own effective level.
+	eventShouldSucceed, err := NewEventFromTrustedJSON(RawJSON(`{
+		"type": "m.room.message",
+		"sender": "@u1:a",
+		"room_id": "!r1:a",
+		"event_id": "$e5:a",
+		"content": {
+			"stuff": "i am a message event"
+		}
+	}`), false, RoomVersionV1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = Allowed(eventShouldSucceed, negativePowerLevelTestRoom); err != nil {
+		t.Error("TestNegativePowerLevels should have succeeded but it didn't:", err)
+	}
+}
diff --git a/eventcontent.go b/eventcontent.go
index 5f9ba63..2fba999 100644
--- a/eventcontent.go
+++ b/eventcontent.go
@@ -429,11 +429,11 @@ func NewPowerLevelContentFromEvent(event *Event) (c PowerLevelContent, err error
 			RedactLevel        levelJSONValue            `json:"redact"`
 			UserLevels         map[string]levelJSONValue `json:"users"`
 			UsersDefaultLevel  levelJSONValue            `json:"users_default"`
 			EventLevels        map[string]levelJSONValue `json:"events"`
 			StateDefaultLevel  levelJSONValue            `json:"state_default"`
-			EventDefaultLevel  levelJSONValue            `json:"event_default"`
+			EventDefaultLevel  levelJSONValue            `json:"events_default"`
 			NotificationLevels map[string]levelJSONValue `json:"notifications"`
 		}
 		if err = json.Unmarshal(event.Content(), &content); err != nil {
 			err = errorf("unparsable power_levels event content: %s", err.Error())
 			return

Vulnerable code: 			EventDefaultLevel  levelJSONValue            `json:"event_default"`
Fixed code: 
var negativePowerLevelTestRoom = &testAuthEvents{
	CreateJSON: json.RawMessage(`{
		"type": "m.room.create",
		"state_key": "",
		"sender": "@u1:a",
		"room_id": "!r1:a",
		"event_id": "$e1:a",
		"content": {
			"room_version": "10"
		}
	}`),
	PowerLevelsJSON: json.RawMessage(`{
		"type": "m.room.power_levels",
		"state_key": "",
		"sender": "@u1:a",
		"room_id": "!r1:a",
		"event_id": "$e3:a",
		"content": {
			"events_default": -9007199254740990,
			"state_default": -9007199254740990,
			"users_default": -9007199254740990,
			"users": {
			}
		}
	}`),
	MemberJSON: map[string]json.RawMessage{
		"@u1:a": json.RawMessage(`{
			"type": "m.room.member",
			"state_key": "@u1:a",
			"sender": "@u1:a",
			"room_id": "!r1:a",
			"event_id": "$e2:a",
			"content": {
				"membership": "join"
			}
		}`),
	},
}

func TestNegativePowerLevels(t *testing.T) {
	// User should be able to demote the user default level
	// below their own effective level.
	eventShouldSucceed, err := NewEventFromTrustedJSON(RawJSON(`{
		"type": "m.room.message",
		"sender": "@u1:a",
		"room_id": "!r1:a",
		"event_id": "$e5:a",
		"content": {
			"stuff": "i am a message event"
		}
	}`), false, RoomVersionV1)
	if err != nil {
		t.Fatal(err)
	}
	if err = Allowed(eventShouldSucceed, negativePowerLevelTestRoom); err != nil {
		t.Error("TestNegativePowerLevels should have succeeded but it didn't:", err)
	}
}
			EventDefaultLevel  levelJSONValue            `json:"events_default"`