Skip to content

security(#146): Fix cross-channel message leak vulnerability#272

Open
anshul23102 wants to merge 1 commit into
chthonn:mainfrom
anshul23102:fix/146-websocket-channel-filtering
Open

security(#146): Fix cross-channel message leak vulnerability#272
anshul23102 wants to merge 1 commit into
chthonn:mainfrom
anshul23102:fix/146-websocket-channel-filtering

Conversation

@anshul23102

Copy link
Copy Markdown

Problem Statement

CRITICAL SECURITY VULNERABILITY: Cross-channel message leak

The WebSocket message handler in server/src/socket/index.js broadcasts messages to any specified channel_id without verifying that the sending user is actually a member of that channel or has permission to access it.

Vulnerability Details

Location: server/src/socket/index.js (lines 166-179)

Issue: The send_message handler broadcasts to any channel without authorization:

socket.on('send_message', (channel_id, message, ...) => {
  socket.to(`channel:${channel_id}`).emit('recieve_message', {...});
});

Attack Scenario:

  1. User A is member of Channel X only
  2. User A discovers Channel Y's ID (through UI or API enumeration)
  3. User A sends: socket.emit('send_message', channelYId, 'malicious message')
  4. Message is broadcast to all users in Channel Y (data leak)

Impact:

  • Users can send messages to channels they're not members of
  • Users can exfiltrate channel data by reading messages from unauthorized channels
  • Cross-channel message leakage enables privilege escalation
  • No audit trail of unauthorized access attempts

Solution Implemented

1. Channel Access Verification Function

Added verifyChannelAccess(userId, channelId, serverId) helper:

  • Validates user membership in channel
  • Handles DMs (direct channel access check)
  • Handles server channels (owner/member verification)
  • Returns true only if user has explicit access
async function verifyChannelAccess(userId, channelId, serverId = null) {
  const chat = await Chat.findById(channelId).lean();
  
  if (chat.type === 'dm') {
    return user1 === userId || user2 === userId;
  }
  
  const server = await Server.findById(serverId).lean();
  const isOwner = server.owner === userId;
  const isMember = server.members.some(m => m.userId === userId);
  return isOwner || isMember;
}

2. Message Send Handler Authorization

Before: No verification
After: Complete authorization chain:

socket.on('send_message', async (channel_id, message, ...) => {
  // 1. Validate inputs
  if (!normalizedChannelId || !userId) return;
  
  // 2. Verify channel access
  const hasAccess = await verifyChannelAccess(userId, normalizedChannelId, serverId);
  if (!hasAccess) {
    console.warn(`[SECURITY] Unauthorized message attempt: User ${userId} to channel ${channelId}`);
    socket.emit('error', { message: 'No access to this channel' });
    return;
  }
  
  // 3. Verify active channel match
  if (socket.data.active_channel_id !== normalizedChannelId) {
    console.warn(`[SECURITY] Channel mismatch for user ${userId}`);
    return;
  }
  
  // 4. Only now broadcast message
  socket.to(`channel:${normalizedChannelId}`).emit('recieve_message', {...});
});

3. Channel Join Handler Authorization

Similar authorization chain for join_chat:

  • Verify user has access before joining
  • Reject unauthorized join attempts
  • Log security violations
  • Provide error feedback

Security Benefits

Issue Before After
Unauthorized Messaging ❌ Possible ✅ Blocked
Data Exfiltration ❌ Possible ✅ Prevented
Channel Enumeration ❌ Undetected ✅ Logged
Access Verification ❌ None ✅ Complete
Audit Trail ❌ None ✅ Full logging

Files Changed

server/src/socket/index.js

Added:

  • verifyChannelAccess() function (25 lines)
  • Chat and Server model imports
  • Authorization logic in send_message (40 lines)
  • Authorization logic in join_chat (35 lines)
  • Security logging and error handling

Removed:

  • Unsafe direct channel broadcasting

Total Changes: +106 lines, -32 lines (net +74)


Testing

Manual Testing Steps

  1. Unauthorized Message Test:

    • User A joins Channel 1 only
    • User A attempts to send message to Channel 2 ID
    • Expected: Message blocked, error logged
    • Actual: ✅ Message blocked, security warning logged
  2. Unauthorized Join Test:

    • User A attempts to join Channel 2 without membership
    • Expected: Join blocked, access denied
    • Actual: ✅ Join blocked, error returned
  3. Authorized Message Test:

    • User A joins Channel 1
    • User A sends message to Channel 1
    • Expected: Message delivered
    • Actual: ✅ Message delivered successfully
  4. Server Owner Access:

    • Server owner sends message to member-only channel
    • Expected: Message delivered (owner has access)
    • Actual: ✅ Message delivered

Security Checklist

  • Authorization verified before message broadcast
  • Channel membership checked before join
  • Active channel verified before operations
  • Unauthorized attempts logged
  • Error messages don't leak information
  • DM channels properly handled
  • Server member verification working
  • Server owner access allowed
  • Comprehensive error handling
  • No bypass paths identified

Deployment Notes

  • No database migrations required
  • No API changes
  • Backward compatible with existing clients
  • Clients receiving error messages on denied access
  • Requires restart to apply Socket.io handler changes
  • Monitor logs for security violation attempts (should be zero)

Related

Type of Change

  • Security fix (critical vulnerability)
  • New feature
  • Bug fix
  • Documentation update

GSSoC Program

Program: GSSoC 2026
Issue: #146
Category: Security / Critical
Impact: Prevents data exfiltration and unauthorized channel access

…horization checks

- Add verifyChannelAccess() function to validate user access before channel operations
- Implement authorization checks in send_message handler
- Require channel membership verification before allowing message transmission
- Add authorization checks in join_chat handler to prevent unauthorized channel access
- Verify active_channel_id matches requested channel_id before operations
- Add comprehensive error logging for security violations
- Prevent users from sending messages to channels they don't have access to
- Prevent users from joining channels they're not a member of
- Add error handling for failed authorization checks

Security Impact:
- Closes critical vulnerability allowing cross-channel message leakage
- Ensures only authorized users can send messages to channels
- Prevents unauthorized channel access
- Adds audit logging for security violation attempts

Fixes chthonn#146
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

@anshul23102 is attempting to deploy a commit to the Sunil Kumar's projects Team on Vercel.

A member of the Team first needs to authorize it.

@anshul23102

Copy link
Copy Markdown
Author

Please add labels:

  • gssoc26 (GSSoC 2026 program)
  • type:security (security fix)
  • priority:critical (critical vulnerability)
  • websocket (WebSocket-related)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Cross-channel message leak — WebSocket handlers don't filter by channel_id

1 participant