CVE-2026-27838 is a low-severity (CVSS 3.1) CWE-639 vulnerability in wger. No vendor fix is recorded yet; mitigation options are listed below.
wger: IDOR via user-unscoped cache keys on routine API actions exposes workout data
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-27838.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
CVE-2026-27838 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 378,156 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
wgerReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
Five 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.
Details
wger/manager/api/views.py — five actions follow this pattern (lines 134–201):
@action(detail=True)
def date_sequence_display_mode(self, request, pk=None):
cache_key = make_routine_api_date_sequence_display_cache_key(pk)
cached = cache.get(cache_key)
if cached:
return Response(cached) # returned WITHOUT calling self.get_object()
# only reaches ownership check on cache miss
routine = self.get_object()
...
Cache key construction in wger/utils/cache.py:89–106:
def make_routine_api_date_sequence_display_cache_key(routine_id):
return f"routine-api-date-sequence-display-{routine_id}"
# No user ID in key
Cache TTL: 1 month (4 * 604800 seconds, settings_global.py:461).
Affected endpoints:
GET /api/v2/routine/{pk}/date-sequence-display/
GET /api/v2/routine/{pk}/date-sequence-gym/
GET /api/v2/routine/{pk}/structure/
GET /api/v2/routine/{pk}/logs/
GET /api/v2/routine/{pk}/stats/
PoC
1. Victim (user A) visits GET /api/v2/routine/5/structure/ → response cached under key "routine-api-structure-5"
2. Attacker (user B) visits GET /api/v2/routine/5/structure/ → cache hit → returns user A's routine structure without any ownership check
Requires the victim to have previously accessed the endpoint (cache must be populated). Once populated, the cache entry is valid for 1 month.
Impact
An 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.
Fix: Include the user ID in the cache key:
def make_routine_api_date_sequence_display_cache_key(routine_id, user_id):
return f"routine-api-date-sequence-display-{user_id}-{routine_id}"
Or move self.get_object() before the cache lookup so ownership is always verified first.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | wger | all versions | No fix |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for wger, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Remediation status
No patched version of wger has shipped for CVE-2026-27838 yet. Where your build allows, override or pin the dependency away from the vulnerable range, and apply any maintainer-recommended mitigation.
Mitigate without a patch
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-27838 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-27838. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-27838 in your dependencies?
O3 Security finds CVE-2026-27838 across PyPI dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.