Severity: moderate
CVSS 4.0: 2.3 (low)
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
Affected versions:
- Apache Wicket (org.apache.wicket:wicket-native-websocket-core) 8.0.0 through
8.19.0
- Apache Wicket (org.apache.wicket:wicket-native-websocket-core) 9.0.0 through
9.24.0
- Apache Wicket (org.apache.wicket:wicket-native-websocket-core) 10.0.0 through
10.11.0
Description:
Insufficient session expiration in Apache Wicket.
org.apache.wicket.protocol.ws.WebSocketSettings#newWebSocketRequest() wraps the
WebSocket upgrade request in an
org.apache.wicket.protocol.ws.api.ServletRequestCopy, which is kept for the
life of the connection and used to build the request for every frame that
arrives on it. Copying the request is deliberate and is documented as such,
because the container recycles the upgrade request once the handshake is over.
The container session is copied along with it, into an
org.apache.wicket.protocol.ws.api.HttpSessionCopy holding the session
attributes as they stood when the connection was opened. That second copy is
not necessary, because a session, unlike a request, is not discarded at the end
of a request. Every frame afterwards resolves its Wicket session through
ISessionStore#lookup(), which reads it out of the copy, so the connection is
detached from the live container session for as long as it stays open.
Ending the session through the container therefore does not end the connection.
After an idle timeout, an HttpSession#invalidate() call made from a filter or
from a security framework, a container-managed logout, or a session
replacement, the connection goes on resolving the org.apache.wicket.Session
instance that existed when it was opened, together with that session's
attributes and, for applications built on wicket-auth-roles, the signed-in
state held on that same instance, so an authorization decision taken inside a
WebSocket callback is taken against an identity that has already been revoked.
The copy is also what the connection writes through: a Session#invalidateNow()
issued from inside a WebSocket callback invalidates the copy and leaves the
container session valid, and session attributes set over the connection are
written to the copy rather than to the session.
An application is affected where it uses Wicket's native WebSocket support on
pages or shared resources that require an authenticated session, and where
sessions are ended by the container rather than by Wicket.
Session#invalidateNow(), and AuthenticatedWebSession#invalidate() and
#signOut() which call it, remain effective for a WebSocketBehavior on a page:
they clear the page manager, and the connection can then no longer resolve the
page it was opened for. A WebSocketResource is not limited in that way, because
a frame naming a resource is served against a throwaway page and never consults
the page manager, so such a connection outlives Wicket's own sign-out as well.
Some containers close WebSocket connections themselves when the HTTP session
they were opened under is destroyed, in which case the connection ends
regardless; that is a property of the container rather than of Wicket.
Applications that do not use the native WebSocket support are not affected.
This issue affects Apache Wicket: from 8.0.0 through 8.19.0, from 9.0.0 through
9.24.0, from 10.0.0 through 10.11.0. Older, unsupported releases from 6.0.0
onwards are also affected. Users are recommended to upgrade to version 8.20.0,
9.25.0 or 10.12.0, which fix the issue.
Credit:
Emond Papegaaij (finder)
References:
https://wicket.apache.org/
https://www.cve.org/CVERecord?id=CVE-2026-82559