matrix-sdk-base is vulnerable to DoS via custom m.room.join_rules event values
Description
matrix-sdk-base is the base component to build a Matrix client library. Versions 0.14.1 and prior are unable to handle responses that include custom m.room.join_rules values due to a serialization bug. This can be exploited to cause a denial-of-service condition, if a user is invited to a room with non-standard join rules, the crate's sync process will stall, preventing further processing for all rooms. This is fixed in version 0.16.0.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
matrix-sdk-base <=0.14.1 has a serialization bug when processing custom m.room.join_rules, allowing a denial-of-service via sync stall.
Vulnerability
Overview
The matrix-sdk-base crate, a core component of the Matrix Rust SDK, fails to gracefully handle room join rules that deviate from the standard values defined in the Matrix specification. Versions up to and including 0.14.1 contain a serialization bug that causes the sync processing to abort when encountering a room with custom m.room.join_rules [1][2]. This means any non-standard join rule accepted by a room (e.g., a custom string like "my_custom_rule") triggers the defect.
Attack
Vector
An attacker only needs to invite a victim user (who is using a vulnerable client) to a room where the join rule has been set to a custom value. No further authentication or special network position is required; the attack can be carried out over any Matrix server that allows creating rooms with custom join rules. Once the victim's client attempts to sync, the malformed room state causes the sync process to stall [1][4]. Critically, this stall prevents processing of subsequent sync data for *all* rooms, not just the problematic one, effectively freezing the entire client's ability to receive new messages or updates.
Impact
Successful exploitation results in a complete denial-of-service condition for the Matrix client. The client becomes unable to process any further sync responses, meaning new messages, room state changes, or any other events will not be handled until the user manually intervenes (e.g., by leaving the offending room or restarting the client without syncing that room). This can be leveraged to silence a user, disrupt communication, or mask other malicious activity in other rooms [4].
Mitigation
The vulnerability is fixed in version 0.16.0 of the matrix-sdk-base crate [1][2][4]. The fix (commit 4ea0418) ensures that custom join rules are not serialized/deserialized in a way that crashes the sync loop, instead treating them as unknown but non-fatal [2]. Users should update to 0.16.0 or later. Clients built on top of a vulnerable version should coordinate with their respective application developers for a patched release.
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
matrix-sdk-basecrates.io | < 0.16.0 | 0.16.0 |
Affected products
2- Range: <=0.14.1
- matrix-org/matrix-rust-sdkv5Range: < 0.16.0
Patches
14ea0418abefafix: Don't attempt to serialize custom join rules (#5924)
3 files changed · +107 −7
crates/matrix-sdk-base/CHANGELOG.md+6 −0 modified@@ -19,6 +19,12 @@ All notable changes to this project will be documented in this file. ## [0.15.0] - 2025-11-27 +### Security Fixes + +- Skip the serialization of custom join rules in the `RoomInfo` which prevented + the processing of sync responses containing events with custom join rules. + ([#5924](https://github.com/matrix-org/matrix-rust-sdk/pull/5924)) + ### Refactor - [**breaking**] Upgrade Ruma to version 0.14.0.
crates/matrix-sdk-base/src/room/room_info.rs+18 −6 modified@@ -217,9 +217,15 @@ impl BaseRoomInfo { AnySyncStateEvent::RoomGuestAccess(g) => { self.guest_access = Some(g.into()); } - AnySyncStateEvent::RoomJoinRules(c) => { - self.join_rules = Some(c.into()); - } + AnySyncStateEvent::RoomJoinRules(c) => match c.join_rule() { + JoinRule::Invite + | JoinRule::Knock + | JoinRule::Private + | JoinRule::Restricted(_) + | JoinRule::KnockRestricted(_) + | JoinRule::Public => self.join_rules = Some(c.into()), + r => warn!("Encountered a custom join rule {}, skipping", r.as_str()), + }, AnySyncStateEvent::RoomCanonicalAlias(a) => { self.canonical_alias = Some(a.into()); } @@ -294,9 +300,15 @@ impl BaseRoomInfo { AnyStrippedStateEvent::RoomGuestAccess(g) => { self.guest_access = Some(g.into()); } - AnyStrippedStateEvent::RoomJoinRules(c) => { - self.join_rules = Some(c.into()); - } + AnyStrippedStateEvent::RoomJoinRules(c) => match &c.content.join_rule { + JoinRule::Invite + | JoinRule::Knock + | JoinRule::Private + | JoinRule::Restricted(_) + | JoinRule::KnockRestricted(_) + | JoinRule::Public => self.join_rules = Some(c.into()), + r => warn!("Encountered a custom join rule {}, skipping", r.as_str()), + }, AnyStrippedStateEvent::RoomCanonicalAlias(a) => { self.canonical_alias = Some(a.into()); }
crates/matrix-sdk/tests/integration/client.rs+83 −1 modified@@ -17,7 +17,8 @@ use matrix_sdk::{ use matrix_sdk_base::{RoomState, sync::RoomUpdates}; use matrix_sdk_common::executor::spawn; use matrix_sdk_test::{ - DEFAULT_TEST_ROOM_ID, JoinedRoomBuilder, SyncResponseBuilder, async_test, + DEFAULT_TEST_ROOM_ID, InvitedRoomBuilder, JoinedRoomBuilder, StateTestEvent, + StrippedStateTestEvent, SyncResponseBuilder, async_test, event_factory::EventFactory, sync_state_event, test_json::{ @@ -61,6 +62,7 @@ use ruma::{ }; use serde_json::{Value as JsonValue, json}; use stream_assert::{assert_next_matches, assert_pending}; +use tempfile::tempdir; use tokio_stream::wrappers::BroadcastStream; use wiremock::{ Mock, Request, ResponseTemplate, @@ -1824,3 +1826,83 @@ async fn test_sync_thread_subscriptions_with_catchup() { let sub3 = room1.load_or_fetch_thread_subscription(&thread3).await.unwrap(); assert_eq!(sub3, Some(matrix_sdk::room::ThreadSubscription { automatic: false })); } + +#[async_test] +#[cfg(feature = "sqlite")] +async fn test_sync_processing_of_custom_join_rule() { + let tempdir = tempdir().unwrap(); + + let room_id = room_id!("!room0:matrix.org"); + + let server = MatrixMockServer::new().await; + let client = server + .client_builder() + .on_builder(|builder| builder.sqlite_store(tempdir.path(), None)) + .build() + .await; + + server + .mock_sync() + .ok(|builder| { + builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_state_event( + StateTestEvent::Custom(json!({ + "content": { + "join_rule": "my_custom_rule" + }, + "event_id": "$15139375513VdeRF:localhost", + "origin_server_ts": 151393755, + "sender": "@example:localhost", + "state_key": "", + "type": "m.room.join_rules", + })), + )); + }) + .mock_once() + .mount() + .await; + + client + .sync_once(Default::default()) + .await + .expect("We should be able to process the sync despite there being a custom join rule"); +} + +#[async_test] +#[cfg(feature = "sqlite")] +async fn test_sync_processing_of_custom_stripped_join_rule() { + let tempdir = tempdir().unwrap(); + + let room_id = room_id!("!room0:matrix.org"); + + let server = MatrixMockServer::new().await; + let client = server + .client_builder() + .on_builder(|builder| builder.sqlite_store(tempdir.path(), None)) + .build() + .await; + + server + .mock_sync() + .ok(|builder| { + builder.add_invited_room(InvitedRoomBuilder::new(room_id).add_state_event( + StrippedStateTestEvent::Custom(json!({ + "content": { + "join_rule": "my_custom_rule" + }, + "event_id": "$15139375513VdeRF:localhost", + "origin_server_ts": 151393755, + "sender": "@example:localhost", + "state_key": "", + "type": "m.room.join_rules", + })), + )); + }) + .mock_once() + .mount() + .await; + + client + .sync_once(Default::default()) + .await + .expect("We should be able to process the sync despite there being a custom join rule"); +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-jj6p-3m75-g2p3ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-66622ghsaADVISORY
- github.com/matrix-org/matrix-rust-sdk/commit/4ea0418abefab2aa93f8851a4d39c723e703e6b0ghsax_refsource_MISCWEB
- github.com/matrix-org/matrix-rust-sdk/pull/5924ghsax_refsource_MISCWEB
- github.com/matrix-org/matrix-rust-sdk/security/advisories/GHSA-jj6p-3m75-g2p3ghsax_refsource_CONFIRMWEB
- rustsec.org/advisories/RUSTSEC-2025-0135.htmlghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.