PT-2026-41506 · Pypi · Wger
Published
2026-05-06
·
Updated
2026-05-06
CVSS v3.1
5.4
Medium
| Vector | AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
Summary
The
trainer login view in wger redirects to request.GET['next'] directly via HttpResponseRedirect() without calling url has allowed host and scheme(). After the trainer successfully enters impersonation mode, their browser is redirected to any attacker-controlled URL supplied in the ?next= parameter, enabling Referer exfiltration and phishing.Details
File:
wger/core/views/user.py, approximately line 203python
# VULNERABLE - wger/core/views/user.py
if not own:
request.session['trainer.identity'] = orig user pk
if request.GET.get('next'):
return HttpResponseRedirect(request.GET['next']) # no host/scheme validationAfter the impersonation logic succeeds, the view performs no validation of the
next parameter before issuing the redirect. An attacker who can deliver a crafted link (e.g. /en/user/2/trainer-login?next=https://evil.example/steal) to a trainer can redirect the trainer's browser to any external host immediately after the impersonation session is established. The Location header contains the raw attacker-controlled URL.Affected endpoint:
GET /en/user/<user pk>/trainer-login->wger.core.views.user.trainer login(the?next=redirect branch)
Suggested patch:
diff
--- a/wger/core/views/user.py
+++ b/wger/core/views/user.py
+from django.utils.http import url has allowed host and scheme
+
if not own:
request.session['trainer.identity'] = orig user pk
- if request.GET.get('next'):
- return HttpResponseRedirect(request.GET['next'])
+ next url = request.GET.get('next')
+ if next url and url has allowed host and scheme(
+ next url, allowed hosts={request.get host()}, require https=request.is secure()
+ ):
+ return HttpResponseRedirect(next url)
return HttpResponseRedirect(reverse('core:index'))Adding
@require POST to trainer login (see also VULN-030) moves the next parameter to the POST body where CSRF protection applies and eliminates the combined CSRF + open-redirect attack surface entirely.PoC
Tested on
wger/server:latest Docker image. Victim: trainer1 (gym.gym trainer permission).Step 1 - Authenticate as trainer:
POST /en/user/login HTTP/1.1
Host: target
Content-Type: application/x-www-form-urlencoded
username=trainer1&password=[REDACTED]&csrfmiddlewaretoken=[REDACTED]
-> 302 Found; Set-Cookie: sessionid=[trainer1 session]Step 2 - Trainer clicks (or is delivered) the crafted link:
GET /en/user/2/trainer-login?next=https://evil.example/steal HTTP/1.1
Host: target
Cookie: sessionid=[trainer1 session]
-> 302 Found
Location: https://evil.example/stealStep 3 - Attacker server logs Referer:
Referer: http://target/en/user/2/trainer-login?next=https://evil.example/steal
(victim user pk and next URL exposed)Reproducibility: 2/2 runs.
Impact
An attacker who can deliver a crafted URL to a trainer (phishing email, malicious gym management system integration, social engineering) can redirect the trainer's browser to an attacker-controlled domain after the trainer enters impersonation mode. The redirect leaks:
- The wger URL structure (including the impersonated user's
user pk) via the browserRefererheader. - The session-rebound cookie (if the attacker page subsequently triggers an authenticated request with
credentials: 'include'targeting wger, any same-site cookie without SameSite=Strict is attached).
Combined with the trainer-login scope bypass (submitted separately), this primitive allows an attacker to silently impersonate arbitrary
gym=None users and then land the trainer on an attacker page for credential harvesting.Affected deployments: every wger instance where
gym.gym trainer is delegated to non-admin users.Severity: Medium (CVSS 5.4). Network-reachable, low complexity, low privilege (trainer role), requires victim interaction (click), scope change (attacker's origin).
Fix
Open Redirect
Found an issue in the description? Have something to add? Feel free to write us 👾
Weakness Enumeration
Related Identifiers
Affected Products
Wger