Summary
The addReaction and removeReaction methods in server/services/core/chat/message.service.ts bypass the checkConversePermission() check that all other message operations use. This allows any authenticated user to add/remove reactions on messages in conversations they are not a member of, by specifying the target message's MongoDB ObjectID.
Vulnerable Code
In message.service.ts, the addReaction method (around line 492) and removeReaction method (around line 533) perform a direct findById(messageId) without any permission verification:
// addReaction - NO permission check
const message = await this.adapter.model.findById(messageId);
// removeReaction - NO permission check
const message = await this.adapter.model.findById(messageId);
Secure Comparison
All other message operations correctly call checkConversePermission() before accessing messages:
sendMessage (line ~201): await this.checkConversePermission(ctx, converseId, groupId)
getMessage / deleteMessage / recallMessage / editMessage / fetchConverseLastMessages / fetchNearbyMessage: All call checkConversePermission()
The checkConversePermission() method (line ~577) validates that the user is either a member of the group's panel, or a participant in the DM conversation.
Impact
- Severity: Medium - Requires valid MongoDB ObjectID (not easily guessable), but allows cross-conversation reaction manipulation
- Any authenticated user can add emoji reactions to messages in private groups/DMs they don't belong to
- Any authenticated user can remove other users' reactions from messages they can't access
- Reveals message existence (side-channel information disclosure)
Suggested Fix
Add checkConversePermission() call at the start of both addReaction and removeReaction:
async addReaction(ctx, messageId, emoji) {
const message = await this.adapter.model.findById(messageId);
if (!message) throw new Error('Message not found');
// Add this permission check:
await this.checkConversePermission(ctx, String(message.converseId), message.groupId ? String(message.groupId) : undefined);
// ... rest of the method
}
Apply the same pattern to removeReaction.
Discovery
Found through automated security research comparing permission patterns across message operation endpoints.
Summary
The
addReactionandremoveReactionmethods inserver/services/core/chat/message.service.tsbypass thecheckConversePermission()check that all other message operations use. This allows any authenticated user to add/remove reactions on messages in conversations they are not a member of, by specifying the target message's MongoDB ObjectID.Vulnerable Code
In
message.service.ts, theaddReactionmethod (around line 492) andremoveReactionmethod (around line 533) perform a directfindById(messageId)without any permission verification:Secure Comparison
All other message operations correctly call
checkConversePermission()before accessing messages:sendMessage(line ~201):await this.checkConversePermission(ctx, converseId, groupId)getMessage/deleteMessage/recallMessage/editMessage/fetchConverseLastMessages/fetchNearbyMessage: All callcheckConversePermission()The
checkConversePermission()method (line ~577) validates that the user is either a member of the group's panel, or a participant in the DM conversation.Impact
Suggested Fix
Add
checkConversePermission()call at the start of bothaddReactionandremoveReaction:Apply the same pattern to
removeReaction.Discovery
Found through automated security research comparing permission patterns across message operation endpoints.