There are two generic solutions to this problem. Both solutions are based on the approach to not publish information in the public that should not be public. This implies that you have to implement some sort of authentication mechanism in your application, e.g. a log in form that creates a new session (and new temporal session keys). Needless to say, you should also use https / wss instead of http / ws.
The first method is to only publish public events, and fetch the private event data over a separate channel (e.g. a new HTTP request). This is what the Stack Exchange does with live inbox notifications: Sockets are only used to notify subscribers of new inbox messages, while the actual content is only fetched over http(s) when the user clicks on the notification bubble.
The second method is to authenticate the Socket.IO connection before storing the socket server-side. In Socket.IO, you can pass extra information with the handshake via the query option. At the server, read this value and only allow users to create the socket upon successful authentication (example accepted answer is for socket.io 0.9, look here for socket.io 1.x). This key should be treated like a session cookie. When the user signs out, the socket associated with this key should be destroyed and the token invalidated. Ideally, this key should be used only once (i.e. invalidated after first use), but that doesn't well in practice if the connection is unreliable and you have to keep reconnecting to Socket.IO.
As an alternative to rejecting the socket (method 2), you could also accept the socket and use the authentication details to control whether a user is allowed to subscribe to an event or join a room. The client will only receive an event if you send it at the server, so if you don't send the event (e.g. because the user is not in the room where the event is broadcast), then there is no leakage of information.