wger: trainer_login accepts GET - CSRF bypass enables forced session rebinding
### Summary The `trainer_login` view in wger accepts GET requests and executes `django_login()` without any CSRF protection, because Django's `CsrfViewMiddleware` only enforces tokens on unsafe methods (POST/PUT/PATCH/DELETE). An attacker can embed a single `` tag on a malicious page; when an authenticated trainer loads that page, their browser auto-issues the GET with the session cookie, forcibly rebinding the trainer's session to an arbitrary user account. ### Details **File**: `wger/core/views/user.py`, approximately lines 161-210 ```python # VULNERABLE - no @require_POST, no request.method == 'POST' guard # CsrfViewMiddleware is bypassed because CSRF enforcement only applies to # unsafe HTTP methods (POST, PUT, PATCH, DELETE) def trainer_login(request, user_pk): ... django_login(request, user, backend='django.contrib.auth.backends.ModelBackend') return HttpResponseRedirect(...) ``` Because the view handles GET, Django's CSRF middleware does not validate any token. An attacker can place `` on any web page. When an authenticated trainer's browser loads that page, it issues the GET request with the session cookie attached (SameSite=Lax does not block same-site top-level navigation and subresource hops triggered by same-origin redirects). The server executes `django_login()` and issues a new session cookie binding the trainer to the victim user. Playwright-verified in Chromium 147: the SameSite bypass occurs via a `?next=` redirect chain - the initial cross-origin subresource
- Products
- wger
- Affected versions
- 1.1, 1.1.1, 1.2, 1.2rc1, 1.3, 1.4, 1.5, 1.6, 1.6.1, 1.7, 1.8, 1.9, 2.0, 2.1
- Fixed versions
- Not specified
- CVEs
- CVE-2026-45161
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 30 Oct 2026, 18:15 UTC · Revision 1
Source evidence
wger: trainer_login accepts GET - CSRF bypass enables forced session rebinding
core-osv · Original sourcePublished 7 Oct 2026, 13:45 UTC
### Summary The `trainer_login` view in wger accepts GET requests and executes `django_login()` without any CSRF protection, because Django's `CsrfViewMiddleware` only enforces tokens on unsafe methods (POST/PUT/PATCH/DELETE). An attacker can embed a single `` tag on a malicious page; when an authenticated trainer loads that page, their browser auto-issues the GET with the session cookie, forcibly rebinding the trainer's session to an arbitrary user account. ### Details **File**: `wger/core/views/user.py`, approximately lines 161-210 ```python # VULNERABLE - no @require_POST, no request.method == 'POST' guard # CsrfViewMiddleware is bypassed because CSRF enforcement only applies to # unsafe HTTP methods (POST, PUT, PATCH, DELETE) def trainer_login(request, user_pk): ... django_login(request, user, backend='django.contrib.auth.backends.ModelBackend') return HttpResponseRedirect(...) ``` Because the view handles GET, Django's CSRF middleware does not validate any token. An attacker can place `` on any web page. When an authenticated trainer's browser loads that page, it issues the GET request with the session cookie attached (SameSite=Lax does not block same-site top-level navigation and subresource hops triggered by same-origin redirects). The server executes `django_login()` and issues a new session cookie binding the trainer to the victim user. Playwright-verified in Chromium 147: the SameSite bypass occurs via a `?next=` redirect chain - the initial cross-origin subresource
osv:GHSA-xf64-4pmc-h8qf
wger
Fixed versions: Not specified
Complete source record
{
"id": "75d2f961aa1444f4d57ed75a61e970bb32091d6ead6b1d6c692466723ef16838",
"url": "https://osv.dev/vulnerability/GHSA-xf64-4pmc-h8qf",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "wger: trainer_login accepts GET - CSRF bypass enables forced session rebinding",
"summary": "### Summary The `trainer_login` view in wger accepts GET requests and executes `django_login()` without any CSRF protection, because Django's `CsrfViewMiddleware` only enforces tokens on unsafe methods (POST/PUT/PATCH/DELETE). An attacker can embed a single `` tag on a malicious page; when an authenticated trainer loads that page, their browser auto-issues the GET with the session cookie, forcibly rebinding the trainer's session to an arbitrary user account. ### Details **File**: `wger/core/views/user.py`, approximately lines 161-210 ```python # VULNERABLE - no @require_POST, no request.method == 'POST' guard # CsrfViewMiddleware is bypassed because CSRF enforcement only applies to # unsafe HTTP methods (POST, PUT, PATCH, DELETE) def trainer_login(request, user_pk): ... django_login(request, user, backend='django.contrib.auth.backends.ModelBackend') return HttpResponseRedirect(...) ``` Because the view handles GET, Django's CSRF middleware does not validate any token. An attacker can place `` on any web page. When an authenticated trainer's browser loads that page, it issues the GET request with the session cookie attached (SameSite=Lax does not block same-site top-level navigation and subresource hops triggered by same-origin redirects). The server executes `django_login()` and issues a new session cookie binding the trainer to the victim user. Playwright-verified in Chromium 147: the SameSite bypass occurs via a `?next=` redirect chain - the initial cross-origin subresource",
"evidence": "osv:GHSA-xf64-4pmc-h8qf",
"products": [
{
"name": {
"value": "wger",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [],
"affected_versions": [
{
"value": "1.1",
"evidence": "/affected/0/versions"
},
{
"value": "1.1.1",
"evidence": "/affected/0/versions"
},
{
"value": "1.2",
"evidence": "/affected/0/versions"
},
{
"value": "1.2rc1",
"evidence": "/affected/0/versions"
},
{
"value": "1.3",
"evidence": "/affected/0/versions"
},
{
"value": "1.4",
"evidence": "/affected/0/versions"
},
{
"value": "1.5",
"evidence": "/affected/0/versions"
},
{
"value": "1.6",
"evidence": "/affected/0/versions"
},
{
"value": "1.6.1",
"evidence": "/affected/0/versions"
},
{
"value": "1.7",
"evidence": "/affected/0/versions"
},
{
"value": "1.8",
"evidence": "/affected/0/versions"
},
{
"value": "1.9",
"evidence": "/affected/0/versions"
},
{
"value": "2.0",
"evidence": "/affected/0/versions"
},
{
"value": "2.1",
"evidence": "/affected/0/versions"
}
]
}
],
"severity": "medium",
"structured": {
"id": "GHSA-xf64-4pmc-h8qf",
"aliases": [
"CVE-2026-45161",
"GHSA-xf64-4pmc-h8qf",
"PYSEC-2026-4317"
],
"metrics": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N"
}
],
"affected": [
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"last_affected": "2.1"
}
]
}
],
"package": {
"name": "wger",
"purl": "pkg:pypi/wger",
"ecosystem": "PyPI"
},
"versions": [
"1.1",
"1.1.1",
"1.2",
"1.2rc1",
"1.3",
"1.4",
"1.5",
"1.6",
"1.6.1",
"1.7",
"1.8",
"1.9",
"2.0",
"2.1"
],
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-xf64-4pmc-h8qf/GHSA-xf64-4pmc-h8qf.json"
}
}
],
"modified": "2026-10-15T14:55:46.505518952Z",
"provider": "osv",
"references": [
"https://github.com/wger-project/wger/security/advisories/GHSA-xf64-4pmc-h8qf",
"https://github.com/wger-project/wger",
"https://github.com/wger-project/wger/releases/tag/2.6"
],
"provider_metadata": {
"cwe_ids": [
"CWE-352"
],
"severity": "MODERATE",
"github_reviewed": true,
"nvd_published_at": null,
"github_reviewed_at": "2026-10-07T13:45:33Z"
}
},
"related_cves": [
{
"value": "CVE-2026-45161",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 332678,
"published_at": "2026-10-07T13:45:33+00:00"
}wger: trainer_login accepts GET - CSRF bypass enables forced session rebinding
core-osv · Original sourcePublished 15 Oct 2026, 10:22 UTC
### Summary The `trainer_login` view in wger accepts GET requests and executes `django_login()` without any CSRF protection, because Django's `CsrfViewMiddleware` only enforces tokens on unsafe methods (POST/PUT/PATCH/DELETE). An attacker can embed a single `` tag on a malicious page; when an authenticated trainer loads that page, their browser auto-issues the GET with the session cookie, forcibly rebinding the trainer's session to an arbitrary user account. ### Details **File**: `wger/core/views/user.py`, approximately lines 161-210 ```python # VULNERABLE - no @require_POST, no request.method == 'POST' guard # CsrfViewMiddleware is bypassed because CSRF enforcement only applies to # unsafe HTTP methods (POST, PUT, PATCH, DELETE) def trainer_login(request, user_pk): ... django_login(request, user, backend='django.contrib.auth.backends.ModelBackend') return HttpResponseRedirect(...) ``` Because the view handles GET, Django's CSRF middleware does not validate any token. An attacker can place `` on any web page. When an authenticated trainer's browser loads that page, it issues the GET request with the session cookie attached (SameSite=Lax does not block same-site top-level navigation and subresource hops triggered by same-origin redirects). The server executes `django_login()` and issues a new session cookie binding the trainer to the victim user. Playwright-verified in Chromium 147: the SameSite bypass occurs via a `?next=` redirect chain - the initial cross-origin subresource
osv:PYSEC-2026-4317
wger
Fixed versions: Not specified
Complete source record
{
"id": "34926cea9a4ab39dc38db5fa7a971b8e84e9317d73cfad0be6a685c1121d1d0d",
"url": "https://osv.dev/vulnerability/PYSEC-2026-4317",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "wger: trainer_login accepts GET - CSRF bypass enables forced session rebinding",
"summary": "### Summary The `trainer_login` view in wger accepts GET requests and executes `django_login()` without any CSRF protection, because Django's `CsrfViewMiddleware` only enforces tokens on unsafe methods (POST/PUT/PATCH/DELETE). An attacker can embed a single `` tag on a malicious page; when an authenticated trainer loads that page, their browser auto-issues the GET with the session cookie, forcibly rebinding the trainer's session to an arbitrary user account. ### Details **File**: `wger/core/views/user.py`, approximately lines 161-210 ```python # VULNERABLE - no @require_POST, no request.method == 'POST' guard # CsrfViewMiddleware is bypassed because CSRF enforcement only applies to # unsafe HTTP methods (POST, PUT, PATCH, DELETE) def trainer_login(request, user_pk): ... django_login(request, user, backend='django.contrib.auth.backends.ModelBackend') return HttpResponseRedirect(...) ``` Because the view handles GET, Django's CSRF middleware does not validate any token. An attacker can place `` on any web page. When an authenticated trainer's browser loads that page, it issues the GET request with the session cookie attached (SameSite=Lax does not block same-site top-level navigation and subresource hops triggered by same-origin redirects). The server executes `django_login()` and issues a new session cookie binding the trainer to the victim user. Playwright-verified in Chromium 147: the SameSite bypass occurs via a `?next=` redirect chain - the initial cross-origin subresource",
"evidence": "osv:PYSEC-2026-4317",
"products": [
{
"name": {
"value": "wger",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [],
"affected_versions": [
{
"value": "1.1",
"evidence": "/affected/0/versions"
},
{
"value": "1.1.1",
"evidence": "/affected/0/versions"
},
{
"value": "1.2",
"evidence": "/affected/0/versions"
},
{
"value": "1.2rc1",
"evidence": "/affected/0/versions"
},
{
"value": "1.3",
"evidence": "/affected/0/versions"
},
{
"value": "1.4",
"evidence": "/affected/0/versions"
},
{
"value": "1.5",
"evidence": "/affected/0/versions"
},
{
"value": "1.6",
"evidence": "/affected/0/versions"
},
{
"value": "1.6.1",
"evidence": "/affected/0/versions"
},
{
"value": "1.7",
"evidence": "/affected/0/versions"
},
{
"value": "1.8",
"evidence": "/affected/0/versions"
},
{
"value": "1.9",
"evidence": "/affected/0/versions"
},
{
"value": "2.0",
"evidence": "/affected/0/versions"
},
{
"value": "2.1",
"evidence": "/affected/0/versions"
}
]
}
],
"severity": "medium",
"structured": {
"id": "PYSEC-2026-4317",
"aliases": [
"CVE-2026-45161",
"GHSA-xf64-4pmc-h8qf",
"PYSEC-2026-4317"
],
"metrics": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N"
}
],
"affected": [
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"last_affected": "2.1"
}
]
}
],
"package": {
"name": "wger",
"purl": "pkg:pypi/wger",
"ecosystem": "PyPI"
},
"versions": [
"1.1",
"1.1.1",
"1.2",
"1.2rc1",
"1.3",
"1.4",
"1.5",
"1.6",
"1.6.1",
"1.7",
"1.8",
"1.9",
"2.0",
"2.1"
],
"database_specific": {
"source": "https://github.com/pypa/advisory-database/blob/main/vulns/wger/PYSEC-2026-4317.yaml"
}
}
],
"modified": "2026-10-15T14:45:10.344591813Z",
"provider": "osv",
"references": [
"https://github.com/wger-project/wger/security/advisories/GHSA-xf64-4pmc-h8qf",
"https://github.com/wger-project/wger",
"https://github.com/wger-project/wger/releases/tag/2.6",
"https://pypi.org/project/wger",
"https://github.com/advisories/GHSA-xf64-4pmc-h8qf",
"https://nvd.nist.gov/vuln/detail/CVE-2026-45161"
]
},
"related_cves": [
{
"value": "CVE-2026-45161",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 332647,
"published_at": "2026-10-15T10:22:46.915403+00:00"
}