{"id":"CVE-2026-27838","aliases":["EUVD-2026-8906","GHSA-42cr-w2gr-m54q","PYSEC-2026-3418"],"status":"published","title":"wger: IDOR via user-unscoped cache keys on routine API actions exposes workout data","description":"wger is a free, open-source workout and fitness manager. Five routine detail action endpoints check a cache before calling `self.get_object()`. In versions up to and including 2.4, ache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check. Commit e964328784e2ee2830a1991d69fadbce86ac9fbf contains a patch for the issue.","severity":{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00294,"percentile":0.22338,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-639"],"published":"2026-02-26T22:04:57Z","modified":"2026-10-28T02:30:48Z","affected":[{"source":"ghsa","ecosystem":"PyPI","package":"wger","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.1"}]}]},{"source":"osv","ecosystem":"PyPI","package":"wger","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.1"}]}],"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"]},{"source":"osv","ecosystem":"PyPI","package":"wger","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.1"}]}],"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"]}],"products":[{"vendor":"wger","product":"wger"},{"vendor":"wger-project","product":"wger"}],"references":[{"url":"https://github.com/wger-project/wger/security/advisories/GHSA-42cr-w2gr-m54q","tags":["x_refsource_CONFIRM","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/wger-project/wger/commit/e964328784e2ee2830a1991d69fadbce86ac9fbf","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-27838","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-42cr-w2gr-m54q","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/27xxx/CVE-2026-27838.json","tags":["advisory"]},{"url":"https://github.com/wger-project/wger","tags":["package"]},{"url":"https://pypi.org/project/wger","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-27838","title":"wger: IDOR via user-unscoped cache keys on routine API actions exposes workout data","description":"wger is a free, open-source workout and fitness manager. Five routine detail action endpoints check a cache before calling `self.get_object()`. In versions up to and including 2.4, ache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check. Commit e964328784e2ee2830a1991d69fadbce86ac9fbf contains a patch for the issue.","status":"published","published":"2026-02-26T22:04:57.968Z","modified":"2026-03-03T01:37:38.975Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low","assessor":"cna"}],"cwes":["CWE-639"],"updated_at":"2026-11-02T14:19:49.199185Z"}],"euvd":[{"id":"EUVD-2026-8906","description":"wger is a free, open-source workout and fitness manager. Five routine detail action endpoints check a cache before calling `self.get_object()`. In versions up to and including 2.4, ache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check. Commit e964328784e2ee2830a1991d69fadbce86ac9fbf contains a patch for the issue.","status":"published","published":"2026-02-26T22:04:57Z","modified":"2026-03-03T01:37:38Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"updated_at":"2026-11-02T19:48:12.247854Z"}],"ghsa":[{"id":"GHSA-42cr-w2gr-m54q","title":"wger: IDOR via user-unscoped cache keys on routine API actions exposes workout data","description":"### Summary\n\nFive routine detail action endpoints check a cache before calling `self.get_object()`. Cache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check.\n\n### Details\n\n`wger/manager/api/views.py` — five actions follow this pattern (lines 134–201):\n\n```python\n@action(detail=True)\ndef date_sequence_display_mode(self, request, pk=None):\n    cache_key = make_routine_api_date_sequence_display_cache_key(pk)\n    cached = cache.get(cache_key)\n    if cached:\n        return Response(cached)   # returned WITHOUT calling self.get_object()\n    # only reaches ownership check on cache miss\n    routine = self.get_object()\n    ...\n```\n\nCache key construction in `wger/utils/cache.py:89–106`:\n\n```python\ndef make_routine_api_date_sequence_display_cache_key(routine_id):\n    return f\"routine-api-date-sequence-display-{routine_id}\"\n    # No user ID in key\n```\n\nCache TTL: 1 month (`4 * 604800` seconds, `settings_global.py:461`).\n\nAffected endpoints:\n```\nGET /api/v2/routine/{pk}/date-sequence-display/\nGET /api/v2/routine/{pk}/date-sequence-gym/\nGET /api/v2/routine/{pk}/structure/\nGET /api/v2/routine/{pk}/logs/\nGET /api/v2/routine/{pk}/stats/\n```\n\n### PoC\n\n```\n1. Victim (user A) visits GET /api/v2/routine/5/structure/ → response cached under key \"routine-api-structure-5\"\n2. Attacker (user B) visits GET /api/v2/routine/5/structure/ → cache hit → returns user A's routine structure without any ownership check\n```\n\nRequires the victim to have previously accessed the endpoint (cache must be populated). Once populated, the cache entry is valid for 1 month.\n\n### Impact\n\nAn attacker with a registered account can retrieve another user's routine details — workout day sequences, exercise structure, training logs, and statistics — from cache without ownership verification.\n\n**Fix**: Include the user ID in the cache key:\n```python\ndef make_routine_api_date_sequence_display_cache_key(routine_id, user_id):\n    return f\"routine-api-date-sequence-display-{user_id}-{routine_id}\"\n```\n\nOr move `self.get_object()` before the cache lookup so ownership is always verified first.","status":"published","published":"2026-02-26T22:15:30Z","modified":"2026-02-27T21:59:41Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-639"],"updated_at":"2026-11-02T14:39:28.962954Z"}],"nvd":[{"id":"CVE-2026-27838","description":"wger is a free, open-source workout and fitness manager. Five routine detail action endpoints check a cache before calling `self.get_object()`. In versions up to and including 2.4, ache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check. Commit e964328784e2ee2830a1991d69fadbce86ac9fbf contains a patch for the issue.","status":"published","published":"2026-02-26T23:16:34.963Z","modified":"2026-06-17T10:27:46.25Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low","assessor":"secondary"},{"version":"3.1","score":3.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N","level":"low","assessor":"primary"}],"cwes":["CWE-639"],"updated_at":"2026-11-02T14:12:07.027269Z"}],"osv":[{"id":"CVE-2026-27838","title":"wger: IDOR via user-unscoped cache keys on routine API actions exposes workout data","description":"wger is a free, open-source workout and fitness manager. Five routine detail action endpoints check a cache before calling `self.get_object()`. In versions up to and including 2.4, ache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check. Commit e964328784e2ee2830a1991d69fadbce86ac9fbf contains a patch for the issue.","status":"published","published":"2026-02-26T22:04:57.968Z","modified":"2026-10-28T02:30:48.573144196Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-639"],"updated_at":"2026-11-02T15:45:00.180685Z"},{"id":"GHSA-42cr-w2gr-m54q","title":"wger: IDOR via user-unscoped cache keys on routine API actions exposes workout data","description":"### Summary\n\nFive routine detail action endpoints check a cache before calling `self.get_object()`. Cache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check.\n\n### Details\n\n`wger/manager/api/views.py` — five actions follow this pattern (lines 134–201):\n\n```python\n@action(detail=True)\ndef date_sequence_display_mode(self, request, pk=None):\n    cache_key = make_routine_api_date_sequence_display_cache_key(pk)\n    cached = cache.get(cache_key)\n    if cached:\n        return Response(cached)   # returned WITHOUT calling self.get_object()\n    # only reaches ownership check on cache miss\n    routine = self.get_object()\n    ...\n```\n\nCache key construction in `wger/utils/cache.py:89–106`:\n\n```python\ndef make_routine_api_date_sequence_display_cache_key(routine_id):\n    return f\"routine-api-date-sequence-display-{routine_id}\"\n    # No user ID in key\n```\n\nCache TTL: 1 month (`4 * 604800` seconds, `settings_global.py:461`).\n\nAffected endpoints:\n```\nGET /api/v2/routine/{pk}/date-sequence-display/\nGET /api/v2/routine/{pk}/date-sequence-gym/\nGET /api/v2/routine/{pk}/structure/\nGET /api/v2/routine/{pk}/logs/\nGET /api/v2/routine/{pk}/stats/\n```\n\n### PoC\n\n```\n1. Victim (user A) visits GET /api/v2/routine/5/structure/ → response cached under key \"routine-api-structure-5\"\n2. Attacker (user B) visits GET /api/v2/routine/5/structure/ → cache hit → returns user A's routine structure without any ownership check\n```\n\nRequires the victim to have previously accessed the endpoint (cache must be populated). Once populated, the cache entry is valid for 1 month.\n\n### Impact\n\nAn attacker with a registered account can retrieve another user's routine details — workout day sequences, exercise structure, training logs, and statistics — from cache without ownership verification.\n\n**Fix**: Include the user ID in the cache key:\n```python\ndef make_routine_api_date_sequence_display_cache_key(routine_id, user_id):\n    return f\"routine-api-date-sequence-display-{user_id}-{routine_id}\"\n```\n\nOr move `self.get_object()` before the cache lookup so ownership is always verified first.","status":"published","published":"2026-02-26T22:15:30Z","modified":"2026-07-13T16:43:12.52722148Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-639"],"updated_at":"2026-11-02T15:46:36.434231Z"},{"id":"PYSEC-2026-3418","title":"wger: IDOR via user-unscoped cache keys on routine API actions exposes workout data","description":"### Summary\n\nFive routine detail action endpoints check a cache before calling `self.get_object()`. Cache keys are scoped only by `pk` — no user ID is included. When a victim has previously accessed their routine via the API, an attacker can retrieve the cached response for the same PK without any ownership check.\n\n### Details\n\n`wger/manager/api/views.py` — five actions follow this pattern (lines 134–201):\n\n```python\n@action(detail=True)\ndef date_sequence_display_mode(self, request, pk=None):\n    cache_key = make_routine_api_date_sequence_display_cache_key(pk)\n    cached = cache.get(cache_key)\n    if cached:\n        return Response(cached)   # returned WITHOUT calling self.get_object()\n    # only reaches ownership check on cache miss\n    routine = self.get_object()\n    ...\n```\n\nCache key construction in `wger/utils/cache.py:89–106`:\n\n```python\ndef make_routine_api_date_sequence_display_cache_key(routine_id):\n    return f\"routine-api-date-sequence-display-{routine_id}\"\n    # No user ID in key\n```\n\nCache TTL: 1 month (`4 * 604800` seconds, `settings_global.py:461`).\n\nAffected endpoints:\n```\nGET /api/v2/routine/{pk}/date-sequence-display/\nGET /api/v2/routine/{pk}/date-sequence-gym/\nGET /api/v2/routine/{pk}/structure/\nGET /api/v2/routine/{pk}/logs/\nGET /api/v2/routine/{pk}/stats/\n```\n\n### PoC\n\n```\n1. Victim (user A) visits GET /api/v2/routine/5/structure/ → response cached under key \"routine-api-structure-5\"\n2. Attacker (user B) visits GET /api/v2/routine/5/structure/ → cache hit → returns user A's routine structure without any ownership check\n```\n\nRequires the victim to have previously accessed the endpoint (cache must be populated). Once populated, the cache entry is valid for 1 month.\n\n### Impact\n\nAn attacker with a registered account can retrieve another user's routine details — workout day sequences, exercise structure, training logs, and statistics — from cache without ownership verification.\n\n**Fix**: Include the user ID in the cache key:\n```python\ndef make_routine_api_date_sequence_display_cache_key(routine_id, user_id):\n    return f\"routine-api-date-sequence-display-{user_id}-{routine_id}\"\n```\n\nOr move `self.get_object()` before the cache lookup so ownership is always verified first.","status":"published","published":"2026-07-13T14:36:39.533532Z","modified":"2026-07-13T16:33:32.429576776Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"updated_at":"2026-11-02T15:52:56.847083Z"}]}}
