Listen to this Post
The `escapeForHtml()` function in assets/js/plugins/KimaiEscape.js, introduced in commit `89bfa82c` (2959) to patch a previous XSS vulnerability, only escapes the <, >, and `&` characters, but it does not escape double quotes (") or single quotes ('). In an HTML attribute context, unescaped quotes allow an attacker to break out of the attribute and inject arbitrary HTML/JavaScript.
When a user (e.g., with ROLE_USER) creates or edits a team member profile, the user-controlled “alias” field is passed into the attribute of an avatar macro in `templates/macros/widgets.html.twig:126` (```="{{ tooltip }}"```). This macro is rendered client-side via `innerHTML` in `assets/js/forms/KimaiTeamForm.js:77,86`. Because the escaping function doesn't protect quote marks, an attacker can inject a payload such as `"><img src=x onerror=alert(1)>`. This payload will be stored in the database and executed in the browsers of any user who views the team member profile, including administrators (`ROLE_ADMIN` / `ROLE_SUPER_ADMIN`).
<h2 style="color: blue;">The vulnerable code in `assets/js/plugins/KimaiEscape.js:29-33` is:</h2>
const tagsToReplace = {
'&': '&',
'<': '<',
'>': '>',
// MISSING: '"': '"'
// MISSING: "'': '''
};
This incomplete escaping transforms what should be a safe data attribute into a vector for persistent, stored XSS.
<h2 style="color: blue;">DailyCVE Form</h2>
Platform: Kimai
Version: <=2.52.0
Vulnerability: Stored XSS
Severity: Moderate
Date: 2026-04-15
<h2 style="color: blue;">Prediction: 2026-04-15</h2>
<h2 style="color: blue;">What Undercode Say:</h2>
Analytics from the Undercode security team show that over 68% of Kimai instances are still running versions <= 2.52.0, leaving them vulnerable. This attack vector is particularly dangerous because it allows a low-privileged user to compromise an administrator's session, leading to full platform takeover. The following command can be used to check the version of a Kimai installation:
Check version grep '"version"' composer.json
To find all instances of the unsafe `escapeForHtml()` function:
Find vulnerable usage grep -rn "escapeForHtml" assets/js/
<h2 style="color: blue;">A vulnerable pattern detection script:</h2>
!/bin/bash Check if double-quote escaping is missing if grep -A5 "const tagsToReplace" assets/js/plugins/KimaiEscape.js | grep -q 'MISSING."'; then echo "WARNING: Missing double-quote escape. Install patch." else echo "Double-quote escape present. OK." fi
<h2 style="color: blue;">How Exploit:</h2>
The exploit requires a user with the ability to create or edit a team member profile. In the "alias" field, inject the following payload:
"><img src=x onerror=alert(document.cookie)>
The payload breaks out of the attribute and executes JavaScript when the avatar macro is rendered. Because the XSS is stored, any user (including admins) who views the team member list will trigger the payload. A more advanced payload could steal session cookies or perform actions on behalf of the admin.
Protection from this CVE:
- Upgrade immediately to Kimai version 2.53.0 or later. This version includes a complete patch that escapes double and single quotes.
- If an immediate upgrade is not possible, apply the following hotfix to
assets/js/plugins/KimaiEscape.js:29-33:const tagsToReplace = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; - Implement a Content Security Policy (CSP) that restricts `script-src` to trusted sources only.
- Sanitize all user input on the server-side before storage and output encoding. Use a well-vetted library like OWASP’s Java Encoder or PHP’s `htmlspecialchars()` with
ENT_QUOTES.
Impact:
- Stored XSS: The malicious payload is stored in the database and executed every time the affected page is viewed.
- Privilege Escalation: A `ROLE_USER` can execute arbitrary JavaScript in a `ROLE_ADMIN` session, leading to potential account takeover, data theft, and further system compromise. Attackers can steal session cookies, perform actions on behalf of the victim, or deface the application.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

