Improper authorisation of /members discloses room membership to non-members
Description
Matrix is an ecosystem for open federated Instant Messaging and Voice over IP. In versions 1.41.0 and prior, unauthorised users can access the membership (list of members, with their display names) of a room if they know the ID of the room. The vulnerability is limited to rooms with shared history visibility. Furthermore, the unauthorised user must be using an account on a vulnerable homeserver that is in the room. Server administrators should upgrade to 1.41.1 or later in order to receive the patch. One workaround is available. Administrators of servers that use a reverse proxy could, with potentially unacceptable loss of functionality, block the endpoints: /_matrix/client/r0/rooms/{room_id}/members with at query parameter, and /_matrix/client/unstable/rooms/{room_id}/members with at query parameter.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
In Synapse ≤1.41.0, unauthorized users can access room member lists in rooms with 'shared' history visibility using a known room ID.
Vulnerability
In Synapse, the Matrix homeserver, versions 1.41.0 and prior contain a vulnerability where unauthorized users can access the membership list (including display names) of a room if they know the room ID. This only affects rooms with shared history visibility, and the attacker must be using an account on a vulnerable homeserver that is in the room. The issue was fixed in version 1.41.1 [1][2].
Exploitation
An attacker must know the room ID and have an account on a vulnerable homeserver that is part of the target room. No authentication beyond a valid account on the same homeserver is required. The attacker can call the /_matrix/client/r0/rooms/{room_id}/members endpoint with an at query parameter (or the unstable equivalent) to retrieve the member list [1].
Impact
Successful exploitation allows an unauthorized user to enumerate room members and their display names, leading to information disclosure that violates the intended access restrictions for rooms with shared history visibility. This could expose sensitive information about room participants [2][3].
Mitigation
Upgrade to Synapse version 1.41.1 or later, released on 2021-08-31, which contains the fix. As a workaround, server administrators using a reverse proxy can block the endpoints /_matrix/client/r0/rooms/{room_id}/members with at query parameter and /_matrix/client/unstable/rooms/{room_id}/members with at query parameter, though this may result in loss of functionality [1][2].
AI Insight generated on May 21, 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-synapsePyPI | < 1.41.1 | 1.41.1 |
Affected products
3- ghsa-coords2 versions
< 1.41.1+ 1 more
- (no CPE)range: < 1.41.1
- (no CPE)range: < 1.43.0-1.1
- matrix-org/synapsev5Range: < 1.41.1
Patches
1cb35df940aMerge pull request from GHSA-jj53-8fmw-f2w2
2 files changed · +59 −2
synapse/groups/groups_server.py+16 −2 modified@@ -332,6 +332,13 @@ async def get_rooms_in_group( requester_user_id, group_id ) + # Note! room_results["is_public"] is about whether the room is considered + # public from the group's point of view. (i.e. whether non-group members + # should be able to see the room is in the group). + # This is not the same as whether the room itself is public (in the sense + # of being visible in the room directory). + # As such, room_results["is_public"] itself is not sufficient to determine + # whether any given user is permitted to see the room's metadata. room_results = await self.store.get_rooms_in_group( group_id, include_private=is_user_in_group ) @@ -341,8 +348,15 @@ async def get_rooms_in_group( room_id = room_result["room_id"] joined_users = await self.store.get_users_in_room(room_id) + + # check the user is actually allowed to see the room before showing it to them + allow_private = requester_user_id in joined_users + entry = await self.room_list_handler.generate_room_entry( - room_id, len(joined_users), with_alias=False, allow_private=True + room_id, + len(joined_users), + with_alias=False, + allow_private=allow_private, ) if not entry: @@ -354,7 +368,7 @@ async def get_rooms_in_group( chunk.sort(key=lambda e: -e["num_joined_members"]) - return {"chunk": chunk, "total_room_count_estimate": len(room_results)} + return {"chunk": chunk, "total_room_count_estimate": len(chunk)} class GroupsServerHandler(GroupsServerWorkerHandler):
tests/rest/client/v2_alpha/test_groups.py+43 −0 added@@ -0,0 +1,43 @@ +from synapse.rest.client.v1 import room +from synapse.rest.client.v2_alpha import groups + +from tests import unittest +from tests.unittest import override_config + + +class GroupsTestCase(unittest.HomeserverTestCase): + user_id = "@alice:test" + room_creator_user_id = "@bob:test" + + servlets = [room.register_servlets, groups.register_servlets] + + @override_config({"enable_group_creation": True}) + def test_rooms_limited_by_visibility(self): + group_id = "+spqr:test" + + # Alice creates a group + channel = self.make_request("POST", "/create_group", {"localpart": "spqr"}) + self.assertEquals(channel.code, 200, msg=channel.text_body) + self.assertEquals(channel.json_body, {"group_id": group_id}) + + # Bob creates a private room + room_id = self.helper.create_room_as(self.room_creator_user_id, is_public=False) + self.helper.auth_user_id = self.room_creator_user_id + self.helper.send_state( + room_id, "m.room.name", {"name": "bob's secret room"}, tok=None + ) + self.helper.auth_user_id = self.user_id + + # Alice adds the room to her group. + channel = self.make_request( + "PUT", f"/groups/{group_id}/admin/rooms/{room_id}", {} + ) + self.assertEquals(channel.code, 200, msg=channel.text_body) + self.assertEquals(channel.json_body, {}) + + # Alice now tries to retrieve the room list of the space. + channel = self.make_request("GET", f"/groups/{group_id}/rooms") + self.assertEquals(channel.code, 200, msg=channel.text_body) + self.assertEquals( + channel.json_body, {"chunk": [], "total_room_count_estimate": 0} + )
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-3x4c-pq33-4w3qghsaADVISORY
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/2VHDEPCZ22GJFMZCWA2XZAGPOEV72POF/mitrevendor-advisoryx_refsource_FEDORA
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PXT7ID7DNBRN2TVTETU3SYQHJKEG6PXN/mitrevendor-advisoryx_refsource_FEDORA
- nvd.nist.gov/vuln/detail/CVE-2021-39164ghsaADVISORY
- github.com/matrix-org/synapse/commit/cb35df940aghsax_refsource_MISCWEB
- github.com/matrix-org/synapse/releases/tag/v1.41.1ghsax_refsource_MISCWEB
- github.com/matrix-org/synapse/security/advisories/GHSA-3x4c-pq33-4w3qghsax_refsource_CONFIRMWEB
- github.com/pypa/advisory-database/tree/main/vulns/matrix-synapse/PYSEC-2021-425.yamlghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/2VHDEPCZ22GJFMZCWA2XZAGPOEV72POFghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/PXT7ID7DNBRN2TVTETU3SYQHJKEG6PXNghsaWEB
News mentions
0No linked articles in our index yet.