Skip to content
Heist/ feed
Back to feed
Medium

wger: trainer_login accepts GET - CSRF bypass enables forced session rebinding

Type: advisorySources: OSV2 source records

### 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 source

Published 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 source

Published 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"
}