CVE-2026-40353 Overview
CVE-2026-40353 is a stored Cross-Site Scripting (XSS) vulnerability affecting wger, a free, open-source workout and fitness manager application. In versions 2.5 and below, the attribution_link property in AbstractLicenseModel constructs HTML by directly interpolating user-controlled license fields (such as license_author) without proper escaping. Templates then render the result using Django's |safe filter, which bypasses automatic HTML escaping. An authenticated user can create an ingredient with a malicious license_author value containing JavaScript, which executes in the browser of any visitor viewing the ingredient page.
Critical Impact
Authenticated attackers can inject malicious JavaScript that executes in browsers of all users viewing compromised ingredient pages, potentially leading to session hijacking, credential theft, or further malicious actions performed on behalf of victims.
Affected Products
- wger Workout Manager version 2.5 and below
Discovery Timeline
- April 17, 2026 - CVE-2026-40353 published to NVD
- April 20, 2026 - Last updated in NVD database
Technical Details for CVE-2026-40353
Vulnerability Analysis
This vulnerability is classified as CWE-79 (Improper Neutralization of Input During Web Page Generation), commonly known as Cross-Site Scripting. The flaw exists in how the wger application handles license attribution information when rendering ingredient pages.
The core issue stems from the attribution_link property within the AbstractLicenseModel class. This property dynamically constructs HTML content by concatenating user-supplied data from license-related fields, specifically the license_author field. The resulting HTML string is then passed to Django templates, where it is rendered using the |safe template filter.
Django's |safe filter instructs the template engine to trust the content and render it without HTML entity encoding. While this filter is sometimes necessary for legitimate HTML content, using it with user-controlled data creates a direct pathway for XSS attacks. Any JavaScript embedded in the license_author field will be executed when the page loads in a visitor's browser.
Root Cause
The root cause is a combination of two security anti-patterns: insufficient input sanitization and improper use of Django's |safe template filter. The AbstractLicenseModel.attribution_link property performs string concatenation with user-controlled fields without HTML encoding, and templates trust this output implicitly by marking it as safe for rendering. This violates the principle of treating all user input as untrusted and ensuring proper output encoding at the presentation layer.
Attack Vector
The attack is network-based and requires low privileges—an authenticated user account is sufficient. The attacker creates or modifies an ingredient entry, injecting malicious JavaScript code into the license_author field. When any user navigates to the ingredient page, the malicious script executes in their browser context. This is a stored XSS attack, meaning the payload persists in the application database and affects all future visitors to the compromised page.
A typical attack payload might include JavaScript that steals session cookies, performs actions on behalf of the victim, redirects users to phishing pages, or modifies page content to deceive users. Because the script runs in the context of the wger application, it has access to any data or functionality available to the victim user.
Detection Methods for CVE-2026-40353
Indicators of Compromise
- Unusual or suspicious content in the license_author field of ingredient records, particularly containing <script> tags, event handlers (e.g., onerror, onload), or JavaScript URLs
- User reports of unexpected browser behavior, redirects, or pop-ups when viewing ingredient pages
- Audit logs showing modifications to ingredient license fields by untrusted or compromised user accounts
- Network traffic from client browsers to unknown external domains when viewing wger pages
Detection Strategies
- Implement Content Security Policy (CSP) headers to detect and block inline script execution, with reporting enabled to capture violation events
- Deploy web application firewall (WAF) rules to flag requests containing common XSS payloads in form submissions
- Perform regular database audits scanning license-related fields for HTML tags and JavaScript patterns
- Enable browser-side XSS auditing and monitor for blocked script execution events
Monitoring Recommendations
- Monitor web server access logs for patterns indicating reconnaissance or XSS testing against ingredient creation endpoints
- Implement application-level logging for all modifications to ingredient records, particularly license attribution fields
- Set up alerts for unusual patterns of ingredient creation or modification by single user accounts
How to Mitigate CVE-2026-40353
Immediate Actions Required
- Upgrade wger to version 2.5 or later, which contains the fix for this vulnerability
- Audit existing ingredient records in the database for malicious content in the license_author and related license fields
- Sanitize or remove any suspicious entries containing HTML or JavaScript code
- Consider temporarily restricting ingredient creation capabilities to trusted users until the patch is applied
Patch Information
This vulnerability has been addressed in wger version 2.5. Users should upgrade to this version or later to remediate the vulnerability. The fix properly escapes user-controlled content before rendering, preventing malicious scripts from executing. For detailed information about the security fix, refer to the GitHub Security Advisory GHSA-6f54-qjvm-wwq3 and the GitHub Release Notes for version 2.5.
Workarounds
- Implement strict Content Security Policy headers that disable inline script execution (script-src 'self') to mitigate XSS impact
- Remove or disable the |safe filter usage in affected templates if source code modifications are feasible
- Restrict ingredient creation and editing permissions to trusted administrators only
- Deploy a web application firewall with XSS filtering rules as an additional defense layer
# Example Content Security Policy header configuration for nginx
# Add to server block in nginx.conf
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none';" always;
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

