Channel authorization re-validated on subscribe, not only at initial handshake
Why it matters
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.
Severity rationale
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.
Remediation
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.
Detection
-
ID:
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 }); });
External references
- cwe · CWE-287 — Improper Authentication
- cwe · CWE-285 — Improper Authorization
- owasp:2021 · A01 — Broken Access Control
Taxons
History
- 2026-04-18·v1.0.0·Initial import from community-realtime·automated