CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-27835

CVE-2026-27835: Do You Even Lift? The wger Workout Leak

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 27, 2026·6 min read·50 visits

Executive Summary (TL;DR)

The wger API forgot to filter database queries by the current user. Authenticated attackers can query specific endpoints to dump the repetition configurations (sets, reps, workout structure) of all users on the instance.

A classic Insecure Direct Object Reference (IDOR) vulnerability in the wger Workout Manager allows authenticated users to access the repetition configurations of every other user on the platform. Due to a failure to filter API querysets by the requesting user, the application serves up the entire database's workout structure to anyone with a valid account.

The Hook: Public Gym, Private Diary?

Let's talk about wger (pronounced however you want, though I lean towards 'wager' that you'll skip leg day). It is the open-source, self-hostable answer to those subscription-heavy fitness apps that hold your data hostage. It manages your workouts, your nutrition, and your progress. It’s a fantastic tool for privacy-conscious gym rats who want to own their data.

But in versions up to 2.4, wger decided that 'community' meant 'radical transparency.' Imagine walking into a gym locker room where every single locker is wide open, and the personal diaries of every member are taped to the doors. That is essentially what happened here.

The vulnerability is a textbook Insecure Direct Object Reference (IDOR), or what the OWASP Top 10 now fancies calling Broken Object Level Authorization (BOLA). While the CVSS score is a modest 4.3 (because apparently, knowing how much your neighbor benches isn't 'Critical' infrastructure damage), the logic flaw represents a fundamental failure in API design. It turns a private workout tracker into a public broadcast system.

The Flaw: The Curse of .all()

Where did the developers go wrong? They fell victim to the path of least resistance in the Django Rest Framework (DRF). DRF is powerful; it automates a lot of the heavy lifting involved in serializing database objects into JSON. But it also gives you enough rope to hang yourself if you aren't paying attention to scoping.

In a proper multi-tenant application (or multi-user, in this case), every single database query regarding user data should have a WHERE clause. You want SELECT * FROM workouts WHERE user_id = current_user. If you forget that WHERE clause, the database happily returns everything.

The flaw in wger was located in the RepetitionsConfigViewSet and MaxRepetitionsConfigViewSet. These views are responsible for serving up the nitty-gritty details of a workout—how many reps, what configuration, etc. Instead of filtering the queryset based on self.request.user, the code simply called .all(). It’s the SQL equivalent of shouting 'EVERYONE!' when asked who is in the room.

The Code: The Smoking Gun

Let’s look at the code. It is almost painful in its simplicity. This is the vulnerable implementation found in wger/manager/api/views.py:

# VULNERABLE CODE
class RepetitionsConfigViewSet(viewsets.ModelViewSet):
    def get_queryset(self):
        # "Here, have everything. I trust you."
        return RepetitionsConfig.objects.all()
 
class MaxRepetitionsConfigViewSet(viewsets.ModelViewSet):
    def get_queryset(self):
        return MaxRepetitionsConfig.objects.all()

See that objects.all()? That is the sound of privacy dying. There is no check to see if the user requesting the data actually owns it. If you have a valid token, you get the list.

Now, let's look at the fix introduced in commit 1fda5690b35706bb137850c8a084ec6a13317b64. The developers switched to a custom base class that likely enforces ownership, and they explicitly filtered the query:

# PATCHED CODE
class RepetitionsConfigViewSet(WgerOwnerObjectModelViewSet):
    def get_queryset(self):
        # "Who are you again? Oh, right. Here is YOUR stuff."
        return RepetitionsConfig.objects.filter(
            slot_entry__slot__day__routine__user=self.request.user
        )

The patch creates a join chain (slot_entry -> slot -> day -> routine -> user) to verify that the config actually belongs to the person asking for it. This is how it should have been from day one.

The Exploit: Skipping Leg Day, Stealing Data

Exploiting this does not require a complex buffer overflow or some wizard-level ROP chain. It requires curl and a registered account. Since wger is often deployed with open registration, the barrier to entry is non-existent.

Step 1: Get in the door. Register an account on the target instance. Log in to get your API token.

Step 2: Ask politely. Send a GET request to the vulnerable endpoint. The API uses sequential IDs (because of course it does), so enumeration is trivial, but you don't even need to iterate IDs here—the list endpoint returns the collection.

# The "Hacker" Tooling
curl -H "Authorization: Token <YOUR_TOKEN>" \
     https://wger-instance.com/api/v2/repetitions-config/

Step 3: Parse the loot. The server responds with a JSON array containing every repetition configuration in the database. You now have the workout structure for every user: specific exercises, rep counts, and routine data. If the IDs are sequential, you can map these configurations back to specific routines and potentially correlate them with specific users if other IDORs exist (which, let's be honest, they probably do).

The Impact: Why Should We Care?

I can hear the detractors now: "So what? They know I do 3 sets of 10. Big deal." And sure, this isn't a dump of credit card numbers or medical records (though health data is protected class in many jurisdictions).

However, consider the context. People use these apps to track progress, physical limitations, and rehabilitation routines. In a competitive environment (say, a sports team using a self-hosted instance), leaking the exact training regimen of your athletes to a rival is a strategic disaster.

Furthermore, this is a privacy violation. Users expect their data to be siloed. If I can see your workout configs, I can infer your activity levels, your schedule, and potentially your location habits if the metadata is rich enough. It is a breach of trust, plain and simple.

The Fix: Authorization is Not Optional

The remediation is straightforward, but it requires diligence. If you are running wger, you need to pull the latest docker image or update your source code immediately. The fix is live in the main branch.

For developers, the lesson is clear: Never trust the client, and never trust the default queryset.

  1. Explicit Filtering: Always override get_queryset in DRF to filter by request.user unless the data is explicitly public.
  2. Test Your Permissions: Write integration tests that attempt to access User A's objects while logged in as User B. If the test passes, your code failed.
  3. Use UUIDs: While not a fix for IDOR, using UUIDs instead of sequential integers makes enumeration significantly more annoying for attackers.

Official Patches

GitHubCommit fixing the permission logic in viewsets

Fix Analysis (1)

Technical Appendix

CVSS Score
4.3/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
EPSS Probability
0.04%

Affected Systems

wger Workout Manager <= 2.4

Affected Versions Detail

Product
Affected Versions
Fixed Version
wger
wger-project
<= 2.4commit 1fda569
AttributeDetail
CWE IDCWE-639
Attack VectorNetwork (API)
CVSS v3.14.3 (Medium)
ImpactInformation Disclosure
Exploit StatusPoC Available
AuthenticationRequired (Low Privilege)

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1078Valid Accounts
Defense Evasion
T1083File and Directory Discovery
Discovery
CWE-639
Authorization Bypass Through User-Controlled Key

Known Exploits & Detection

GitHub AdvisoryPoC demonstrating enumeration of repetition configs via curl

Vulnerability Timeline

Vulnerability Disclosed (GHSA)
2026-02-26
Patch Committed
2026-02-26
PoC Published
2026-02-26

References & Sources

  • [1]GHSA-xf68-8hjw-7mpm: Exposure of repetition configuration
  • [2]wger Project Homepage

More Reports

•about 1 hour ago•GHSA-4HV6-XC92-J86G
6.5

GHSA-4HV6-XC92-J86G: Insufficient Session Expiration in Vikunja WebSocket Authentication Pipeline

Vikunja versions 2.3.0 through 2.6.0 contain an insufficient session expiration vulnerability (CWE-613) within the WebSocket authentication handler. Although Vikunja enforces server-side session tracking and revocation for REST API routes, the WebSocket handshake handler validates cryptographic JWT signatures without querying the database session state. Consequently, revoked JWT tokens can establish new real-time WebSocket connections, and existing connections persist after session revocation.

Alon Barad
Alon Barad
2 views•5 min read
•about 2 hours ago•GHSA-FPRF-R6RV-XG99
6.5

GHSA-FPRF-R6RV-XG99: Cross-Tenant Task Position Recalculation in Vikunja

A cross-tenant boundary breach vulnerability in Vikunja allows an authenticated user to trigger global task position recalculations across all tenant instances by creating a saved filter with an empty filter string payload.

Amit Schendel
Amit Schendel
5 views•4 min read
•about 3 hours ago•GHSA-HJX8-QV73-F7CM
6.5

GHSA-HJX8-QV73-F7CM: Incomplete Access Revocation Leading to Webhook Data Exfiltration in Vikunja

An access revocation flaw in Vikunja allows removed collaborators to retain outbound webhooks and link shares created prior to revocation, enabling persistent exfiltration of sensitive task data.

Alon Barad
Alon Barad
5 views•5 min read
•about 4 hours ago•GHSA-PJR3-86V4-5P7W
5.4

GHSA-PJR3-86V4-5P7W: Broken Access Control via MAX Aggregation in Vikunja Subtree Permissions

Vikunja v2.6.0 contains a permission inheritance regression in pkg/models/project_access.go where explicit down-restrictions on sub-projects are overridden by higher parent project permissions due to MAX aggregation across project tree nodes.

Alon Barad
Alon Barad
5 views•6 min read
•about 5 hours ago•GHSA-FMMF-XQ98-G327
5.3

GHSA-fmmf-xq98-g327: Write-Level Project Members Can Delete Admin-Tier Link Shares in Vikunja

An authorization bypass vulnerability in Vikunja's link share deletion handlers allows project members with Write privileges to delete Admin-tier link shares. The handler passes an unpopulated struct to the authorization check, causing the permission evaluation to fall back to default Write permissions instead of requiring Admin privileges.

Alon Barad
Alon Barad
8 views•5 min read
•about 6 hours ago•GHSA-M687-P538-R5HP
7.2

GHSA-m687-p538-r5hp: Permissive Localhost CORS Policy Leads to Account Takeover in Vikunja

Vikunja versions 2.2.0 through 2.6.0 contain a Cross-Origin Resource Sharing (CORS) misconfiguration flaw in `code.vikunja.io/api`. Default configurations permit wildcard origins for localhost (`http://127.0.0.1:*` and `http://localhost:*`) with credentialed requests (`Access-Control-Allow-Credentials: true`). Because configuring a public service URL appends to this default list rather than overriding it, production environments inadvertently trust all local origins. A local page or application on a user's machine can execute a credentialed cross-origin request to the token refresh endpoint, extract the returned JWT access token, and achieve complete account takeover.

Alon Barad
Alon Barad
8 views•5 min read