Overview
This advisory addresses a security vulnerability in DPGW’s own authentication layer (not a third-party dependency). Under specific authentication configurations, the authenticated user identity can leak from one HTTP request to a subsequent request served by the same pooled worker thread, allowing one user’s request to be processed under another user’s identity.
Vulnerability Details
- CVE ID: None (internally identified)
- Component: DPGW Security Manager (
org.medoro.dpgw.base.priv.security2.SecurityManager2) and the request authentication filters (Security2FilterHandler,AuthFilter, and the ESB / OAuth2 / GoldDigger login handlers) - Vulnerability Class: CWE-488 (Exposure of Data Element to Wrong Session) / CWE-384 (Session Fixation) / improper cleanup of thread-local security context on a pooled thread
- Severity Score: 7.8 High (
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N)
Affected Versions of DPGW
Affected only when ESB authentication or OAuth2 authentication is enabled (the GoldDigger “open” authentication filter shares the same defect).
- 1.11 — all releases (<= 1.11.47-REL), no fix yet
- 1.12 — all releases (<= 1.12.51-REL), no fix yet
- 1.13 — releases <= 1.13.29-REL (fixed on the branch, ships in the next 1.13.x release)
- 1.14 — all releases (<= 1.14.08-REL), no fix yet
- main / devel — unreleased, not yet fixed
Risk Assessment & Applicability
Usage
DPGW authenticates HTTP requests through a chain of servlet filters. The authenticated Principal is held per-thread in a ThreadLocal<Principal> inside SecurityManager2 (login() sets it, logout() clears it via ThreadLocal.remove()). Requests are served by pooled Jetty worker threads, so the thread-local must be cleared at the end of every request; otherwise the value persists on the thread and is visible to whatever request the pool assigns to that thread next.
Clearing is performed by AuthFilter in finally { sm2.logout(); } blocks — but only on the request paths that flow through chain.doFilter(...). The trusted-user login sink used by the federated login flows, TrustedUserAuthenticateAction.authenticateAndLoginToSession(), calls sm.login(principal) (populating the thread-local) and stores the principal in the HTTP session, but is not paired with a scoped logout.
Analysis
The ESB, OAuth2 and GoldDigger login flows complete the request by writing a redirect/response and returning without calling chain.doFilter(...), so AuthFilter‘s cleanup finally blocks are never reached:
- ESB:
ESBTokenAuthFilterHandler.filterAction()(/openviewer) →authenticateAndLoginToSession()(→sm.login) →filterAction.sendRedirect(...)and return. Nologout(), nochain(). - OAuth2:
OAuth2AuthorizeServletV1(/public/auth/v1/oauth2/authorize/*) →AuthorizeHandler.loginUser()→OAuth2Login.loginUser()→authenticateAndLoginToSession()(→sm.login). Because the endpoint is under/public/...,AuthFilterroutes it through itselsebranch, which chains without afinally-logout. - GoldDigger:
GoldDiggerAuthenticationWebFilter.filterAction()(/openzauth/*) — same login-then-redirect pattern.
After such a login request completes, the ESB/OAuth2/GoldDigger user’s Principal remains in the thread-local on that Jetty worker thread. When the pool next assigns that thread to a different, otherwise-unauthenticated request, the security layer treats the request as already authenticated as the leftover user — the trust points that read the thread-local instead of re-deriving identity from the request/session are AuthFilter (if (sm2.getCurrentPrincipal().isPresent()) { ... }) and OAuth2AuthorizeServletV1 (sm.getCurrentPrincipal().isPresent()).
The exposure window is the first reuse of that thread shortly after a successful login: the request that inherits the identity is served under it and then logs out, clearing the value. An attacker cannot control which pooled thread serves their request and cannot force the timing, so exploitation is a race dependent on a concurrent legitimate login (reflected in AC:H). When it succeeds, the impact is full impersonation of the affected user — read access to that user’s data and the ability to act as them — hence C:H/I:H. There is no availability impact.
Status
Affected
Severity Score in the context of DPGW: 7.8 High CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
Network-reachable (AV:N) with no attacker credentials required (PR:N). Attack complexity is High (AC:H) because success requires winning a race for the specific pooled thread immediately after a victim’s federated login. The identity takeover yields high confidentiality and integrity impact (C:H/I:H) against a medical imaging system; no availability impact (A:N).
Impact on DPGW
When ESB or OAuth2 authentication is enabled, a request can be processed under a different user’s identity for the first reuse of a pooled worker thread following that user’s login. This constitutes an authentication/authorization bypass: the inheriting request gains the leftover user’s roles and data access, enabling unauthorized viewing of another user’s studies/patient data and actions performed under their identity. Deployments that do not enable ESB or OAuth2 (or GoldDigger open) authentication are not affected.
Remediation & Mitigations
Fix
The fix ensures the thread-local security context is always cleared at the end of every request, regardless of which handler performed the login, by wrapping the outermost /* filter handler’s request processing in a finally { sm.logout(); }:
– 1.13 — commit d42c8925c3 (“fix(Security): ensure proper logout in Security2FilterHandler”); ships in the next 1.13.x release (after 1.13.29-REL).
Because Security2FilterHandler is the outermost /* handler, its finally-logout runs even when an inner ESB/OAuth2/GoldDigger handler short-circuits with a redirect, so it covers all of the leaking paths.
Scheduled fix
The same fix is to be ported to the remaining maintained branches:
- 1.14 — 1.14.09-REL (2026-07-28)
- 1.12 — 1.12.53-REL (2026-07-23)
- 1.11 — pending
- main / devel — pending
User Actions
- Interim mitigation: if ESB, OAuth2 or GoldDigger open authentication is not required, disable it until the patched release is deployed. Deployments using only standard cookie/session or DPGW-token authentication (whose paths already clear the thread-local) are not exposed.
- Upgrade to a DPGW release containing the fix once available for the branch in use.