A handshake-only authorization model is susceptible to time-of-check/time-of-use attacks: a user whose channel access is revoked after connecting can continue subscribing to restricted channels until the connection drops. CWE-285 (Improper Authorization) and OWASP A01 (Broken Access Control) both describe this failure — authorization decisions must be re-evaluated at the point of access, not cached from an earlier check. In a community app, this means a banned user or a user whose subscription lapses can still join private channels by issuing subscribe events on an existing connection.
Critical because a user whose access was revoked post-handshake can subscribe to restricted channels until the TCP connection drops, bypassing OWASP A01 access controls.
Re-check channel permissions on every subscribe event, not only at connection time. Emit an error and skip socket.join() if the check fails.
socket.on('subscribe', async (channel: string) => {
const allowed = await checkChannelAccess(socket.userId, channel);
if (!allowed) {
socket.emit('error', { code: 403, message: 'Forbidden', channel });
return;
}
socket.join(channel);
socket.emit('subscribed', { channel });
});
Never trust client-side authorization state. The server must be the sole authority on channel membership.
ID: community-realtime.connection-management.channel-auth-revalidation
Severity: critical
What to look for: Count all subscribe event handlers. For each, classify whether user permission is re-validated before emitting messages. Enumerate the authorization checks present per handler.
Pass criteria: The subscribe handler validates that the user has permission to access the target channel before emitting any messages. 100% of subscribe handlers must re-validate permissions. Authorization must not rely solely on the initial handshake.
Fail criteria: Channel access is only checked at initial handshake, or no per-channel authorization is implemented.
Do NOT pass when: Authorization is checked only via client-side logic that the server trusts without verification — client-side-only auth is NOT a pass.
Skip (N/A) when: Never — channel-level authorization is critical for multi-channel systems.
Cross-reference: For authorization patterns and permission models, the Auth & Session Audit covers role-based access control.
Detail on fail: "Subscribe handler does not re-validate channel permissions. User granted permission at handshake could subscribe to restricted channels later."
Remediation: Validate channel access on every subscribe request:
socket.on('subscribe', async (channel: string) => {
const userId = socket.userId;
const hasAccess = await checkChannelAccess(userId, channel);
if (!hasAccess) {
socket.emit('error', { message: 'Forbidden', channel });
return;
}
socket.join(channel);
socket.emit('subscribed', { channel });
});