From 27fb5e51dedfe7e11aa8eb57754e8ee5332daa85 Mon Sep 17 00:00:00 2001 From: BruebachL <44814898+BruebachL@users.noreply.github.com> Date: Sat, 8 Aug 2026 17:32:39 +0200 Subject: [PATCH] [Security] Redact sensitive user data from client-visible responses (#7077) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The getUserInfo command for a user that is not currently online returned the full database record, including the account id, the email address and the stored client id, to any logged-in requester. Mirror the redaction already applied to online users via copyUserInfo(): the id and email are only ever exposed to the account owner, and the client id only to moderators. The buddy/ignore add-to-list event likewise returned the target user's email address and client id to the requester. The list entry only needs the public profile fields, so strip the email and client id from it as well. Co-authored-by: Lukas BrĂ¼bach --- .../network/server/remote/server_protocolhandler.cpp | 9 +++++++++ servatrice/src/serversocketinterface.cpp | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp b/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp index c441da781..c3686ddfa 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp @@ -685,6 +685,15 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetU ServerInfo_User_Container *infoSource = server->findUser(userName); if (!infoSource) { re->mutable_user_info()->CopyFrom(databaseInterface->getUserData(userName, true)); + // The user is not currently online. Mirror the redaction that + // copyUserInfo() applies to online users: the id and email address + // are only ever visible to the account owner, and the client id + // only to moderators. + re->mutable_user_info()->clear_id(); + re->mutable_user_info()->clear_email(); + if (!(userInfo->user_level() & ServerInfo_User::IsModerator)) { + re->mutable_user_info()->clear_clientid(); + } } else { re->mutable_user_info()->CopyFrom( infoSource->copyUserInfo(true, false, userInfo->user_level() & ServerInfo_User::IsModerator)); diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 6ceebfca9..842ddb4c8 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -325,6 +325,10 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAddToList(const Command Event_AddToList event; event.set_list_name(cmd.list()); event.mutable_user_info()->CopyFrom(databaseInterface->getUserData(user)); + // The buddy/ignore list entry is only used to display the user's basic + // profile: never leak the target's email address or client id. + event.mutable_user_info()->clear_email(); + event.mutable_user_info()->clear_clientid(); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); return Response::RespOk;