CVE-2023-43796: Insufficient Information (NVD-CWE-noinfo)
value: Synapse is an open-source Matrix homeserver Prior to versions 1.95.1 and 1.96.0rc1, cached device information of remote users can be queried from Synapse. This can be used to enumerate the remote users known to a homeserver. System administrators are encouraged to upgrade to Synapse 1.95.1 or 1.96.0rc1 to receive a patch. As a workaround, the `federation_domain_whitelist` can be used to limit federation traffic with a homeserver.

CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 5.3
Published: 2023-10-31T17:15Z
Repository: https://github.com/matrix-org/synapse
Language: Python
Files changed: synapse/federation/federation_server.py, synapse/handlers/device.py, synapse/handlers/e2e_keys.py
Commit date: 2023-10-31 13:59:09 +0000
Commit message: Merge pull request from GHSA-mp92-3jfm-3575


Diff: diff --git a/synapse/federation/federation_server.py b/synapse/federation/federation_server.py
index 6ac8d16095..356ab0492b 100644
--- a/synapse/federation/federation_server.py
+++ b/synapse/federation/federation_server.py
@@ -82,11 +82,11 @@ from synapse.replication.http.federation import (
     ReplicationGetQueryRestServlet,
 )
 from synapse.storage.databases.main.lock import Lock
 from synapse.storage.databases.main.roommember import extract_heroes_from_room_summary
 from synapse.storage.roommember import MemberSummary
-from synapse.types import JsonDict, StateMap, get_domain_from_id
+from synapse.types import JsonDict, StateMap, get_domain_from_id, UserID
 from synapse.util import unwrapFirstError
 from synapse.util.async_helpers import Linearizer, concurrently_execute, gather_results
 from synapse.util.caches.response_cache import ResponseCache
 from synapse.util.stringutils import parse_server_name
 
@@ -997,10 +997,16 @@ class FederationServer(FederationBase):
 
     @trace
     async def on_claim_client_keys(
         self, query: List[Tuple[str, str, str, int]], always_include_fallback_keys: bool
     ) -> Dict[str, Any]:
+        if any(
+            not self.hs.is_mine(UserID.from_string(user_id))
+            for user_id, _, _, _ in query
+        ):
+            raise SynapseError(400, "User is not hosted on this homeserver")
+
         log_kv({"message": "Claiming one time keys.", "user, device pairs": query})
         results = await self._e2e_keys_handler.claim_local_one_time_keys(
             query, always_include_fallback_keys=always_include_fallback_keys
         )
 
diff --git a/synapse/handlers/device.py b/synapse/handlers/device.py
index 544bc7c13d..b0f6011629 100644
--- a/synapse/handlers/device.py
+++ b/synapse/handlers/device.py
@@ -326,10 +326,13 @@ class DeviceWorkerHandler:
         log_kv(result)
 
         return result
 
     async def on_federation_query_user_devices(self, user_id: str) -> JsonDict:
+        if not self.hs.is_mine(UserID.from_string(user_id)):
+            raise SynapseError(400, "User is not hosted on this homeserver")
+
         stream_id, devices = await self.store.get_e2e_device_keys_for_federation_query(
             user_id
         )
         master_key = await self.store.get_e2e_cross_signing_key(user_id, "master")
         self_signing_key = await self.store.get_e2e_cross_signing_key(
diff --git a/synapse/handlers/e2e_keys.py b/synapse/handlers/e2e_keys.py
index 8c6432035d..5a0c1f47be 100644
--- a/synapse/handlers/e2e_keys.py
+++ b/synapse/handlers/e2e_keys.py
@@ -540,10 +540,16 @@ class E2eKeysHandler:
                     key info.
         """
         device_keys_query: Dict[str, Optional[List[str]]] = query_body.get(
             "device_keys", {}
         )
+        if any(
+            not self.is_mine(UserID.from_string(user_id))
+            for user_id in device_keys_query
+        ):
+            raise SynapseError(400, "User is not hosted on this homeserver")
+
         res = await self.query_local_devices(
             device_keys_query,
             include_displaynames=(
                 self.config.federation.allow_device_name_lookup_over_federation
             ),

Vulnerable code: from synapse.types import JsonDict, StateMap, get_domain_from_id
Fixed code: from synapse.types import JsonDict, StateMap, get_domain_from_id, UserID
        if any(
            not self.hs.is_mine(UserID.from_string(user_id))
            for user_id, _, _, _ in query
        ):
            raise SynapseError(400, "User is not hosted on this homeserver")

        if not self.hs.is_mine(UserID.from_string(user_id)):
            raise SynapseError(400, "User is not hosted on this homeserver")

        if any(
            not self.is_mine(UserID.from_string(user_id))
            for user_id in device_keys_query
        ):
            raise SynapseError(400, "User is not hosted on this homeserver")