CVE-2021-21396 (Other, published 2021-03-26T22:15Z)
Description: value: wire-server is an open-source back end for Wire, a secure collaboration platform. In wire-server from version 2021-02-16 and before version 2021-03-02, the client metadata of all users was exposed in the `GET /users/list-clients` endpoint. The endpoint could be used by any logged in user who could request client details of any other user (no connection required) as far as they can find their User ID. The exposed metadata included id, class, type, location, time, and cookie. A user on a Wire backend could use this endpoint to find registration time and location for each device for a given list of users. As a workaround, remove `/list-clients` from nginx config. This has been fixed in version 2021-03-02.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-200 \u2014 Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
Repository: https://github.com/wireapp/wire-server
Files changed:
libs/wire-api/src/Wire/API/User/Client.hs
libs/wire-api/src/Wire/API/UserMap.hs
libs/wire-api/test/unit/Test/Wire/API/Swagger.hs
services/brig/src/Brig/API/Public.hs
services/brig/test/integration/API/User/Client.hs
Commit message: Return PubClient instead of Client from /users/list-clients (#1391)



Vulnerable code:
  deriving stock (Eq, Show, Generic)
import Wire.API.User.Client (Client)
  deriving newtype (Semigroup, Monoid, ToJSON, FromJSON)
instance ToSchema (UserMap (Set Client)) where
    mapSch <- declareSchema (Proxy @(Map UserId (Set Client)))
      NamedSchema (Just "UserMap (Set Client)") $
          & description ?~ "Map of UserId to (Set Client)"
          & example ?~ toJSON (Map.singleton (generateExample @UserId) (Set.singleton (generateExample @Client)))
      testToJSON @(Client.UserClientMap (Maybe Prekey.Prekey)),
      testToJSON @Client.UserClients,
    :> Post '[Servant.JSON] (Public.QualifiedUserMap (Set Public.Client))
listClientsBulk :: UserId -> Range 1 MaxUsersForListClientsBulk [Qualified UserId] -> Handler (Public.QualifiedUserMap (Set Public.Client))
listClientsBulk _zusr limitedUids =
  API.lookupClientsBulk (fromRange limitedUids) !>> clientError
  let expectedResponse :: QualifiedUserMap (Set Client) =
                Map.fromList [(uid1, Set.fromList [c11, c12, c13]), (uid2, Set.fromList [c21, c22])]

Fixed code:
  deriving stock (Eq, Show, Generic, Ord)
  deriving (ToSchema) via (CustomSwagger '[FieldLabelModifier (StripPrefix "pubClient", LowerCase)] PubClient)
  deriving newtype (Semigroup, Monoid, ToJSON, FromJSON, Functor)
instance Functor QualifiedUserMap where
  fmap f (QualifiedUserMap qMap) =
    QualifiedUserMap $ f <$$> qMap

instance (Typeable a, ToSchema a, ToJSON a, Arbitrary a) => ToSchema (UserMap (Set a)) where
    mapSch <- declareSchema (Proxy @(Map UserId (Set a)))
    let valueTypeName = Text.pack $ show $ typeRep $ Proxy @a
      NamedSchema (Just $ "UserMap (Set " <> valueTypeName <> ")") $
          & description ?~ "Map of UserId to (Set " <> valueTypeName <> ")"
          & example ?~ toJSON (Map.singleton (generateExample @UserId) (Set.singleton (generateExample @a)))
      testToJSON @Client.PubClient,
      testToJSON @(UserMap.UserMap (Set Client.PubClient)),
      testToJSON @(Client.UserClientMap (Maybe Prekey.Prekey)),
      testToJSON @Client.UserClients,
import qualified Data.Set as Set
    :> Post '[Servant.JSON] (Public.QualifiedUserMap (Set Public.PubClient))
listClientsBulk :: UserId -> Range 1 MaxUsersForListClientsBulk [Qualified UserId] -> Handler (Public.QualifiedUserMap (Set Public.PubClient))
listClientsBulk _zusr limitedUids = do
  Set.map API.pubClient <$$> API.lookupClientsBulk (fromRange limitedUids) !>> clientError
  let mkPubClient cl = PubClient (clientId cl) (clientClass cl)
  let expectedResponse :: QualifiedUserMap (Set PubClient) =
                Map.fromList
                  [ (uid1, Set.fromList $ mkPubClient <$> [c11, c12, c13]),
                    (uid2, Set.fromList $ mkPubClient <$> [c21, c22])
                  ]