When a client that is connected via websockets gets a sudden disconnect (without sending proper stream close elements etc), then the session disappearance isn't handled properly.
Notably, if the client was in a MUC room on the local server, it will remain in that room indefinitely.
This problem might also affect clients that connect via BOSH / HTTP Binding (I did not test this) but does not affect clients connecting through sockets.
The problem appears to involve this snippet in org.jivesoftware.openfire.SessionManager.ClientSessionListener#onConnectionClose:
The routingTable.hasClientRoute(session.getAddress()) statement unexpectedly evaluates to false for websocket connections (it's true for socket connections), which prevents a presence update for this session to be sent. As the MUC room was joined with a directed presence, it depends on this snippet to detect that the user left.
Older code suggests that org.jivesoftware.openfire.SessionManager.ClientSessionListener#onConnectionClose is to be called prior to removing the session, not after.