VYPR
Low severityNVD Advisory· Published Aug 31, 2021· Updated Aug 4, 2024

Improper authorisation of /members discloses room membership to non-members

CVE-2021-39164

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.

PackageAffected versionsPatched versions
matrix-synapsePyPI
< 1.41.11.41.1

Affected products

3

Patches

1
cb35df940a

Merge pull request from GHSA-jj53-8fmw-f2w2

https://github.com/matrix-org/synapsereivilibreAug 31, 2021via ghsa
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

News mentions

0

No linked articles in our index yet.