An unauthenticated WebSocket endpoint is an open data tap. Any client — including malicious actors scanning for open sockets — can connect and receive the full message stream without possessing a valid session. OWASP A07 (Identification & Authentication Failures) and CWE-287 both flag authentication bypasses as severe because they eliminate every downstream access control you've built. In a community platform this means private channel conversations, direct messages, and presence events are exposed to anonymous consumers the moment the server boots.
Critical because any unauthenticated client receives the full real-time message stream, bypassing every downstream access control.
Add a Socket.IO middleware that validates the bearer token on the handshake before the connection is established. Reject with an error — never open the stream first and check later.
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) return next(new Error('Missing authentication token'));
try {
socket.userId = verifyToken(token).id;
next();
} catch {
next(new Error('Invalid token'));
}
});
For SSE endpoints, validate the session cookie or Authorization header in your HTTP route handler before writing the Content-Type: text/event-stream response header.
ID: community-realtime.connection-management.websocket-auth-required
Severity: critical
What to look for: Enumerate all WebSocket/SSE connection handlers. For each, classify whether authentication is checked before data is sent. Count the total handlers and how many validate credentials on the initial handshake. Quote the actual middleware or auth check if found.
Pass criteria: The WebSocket or SSE handler checks authentication credentials (token, session, cookie) before establishing the connection. 100% of connection handlers must validate credentials. Unauthenticated connection attempts are rejected with an error response. Report even on pass: "Found N connection handlers — all validate auth before streaming."
Fail criteria: The connection handler accepts connections without validating authentication, or authentication is checked only after messages start flowing.
Do NOT pass when: Authentication is present but only checks a static API key rather than a per-user credential — static keys shared across all users are NOT a pass for this check.
Skip (N/A) when: Never — all real-time connections must be authenticated.
Detail on fail: Describe the authentication gap. Example: "WebSocket handler accepts connections with no token validation. Any client can connect and receive messages."
Remediation: Real-time connections expose sensitive message streams. Always authenticate before opening the connection. In Express with Socket.IO:
import { Server as SocketIOServer } from 'socket.io';
const io = new SocketIOServer(server, {
transports: ['websocket'],
});
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Missing authentication token'));
}
try {
const user = verifyToken(token);
socket.userId = user.id;
next();
} catch (err) {
next(new Error('Invalid token'));
}
});
io.on('connection', (socket) => {
console.log(`User ${socket.userId} connected`);
});
For SSE, validate in your HTTP route handler before opening the stream.