VYPR
Moderate severityNVD Advisory· Published Dec 1, 2021· Updated Aug 3, 2024

Cross-site Scripting (XSS) - Stored in kevinpapst/kimai2

CVE-2021-3983

Description

Kimai2 before 1.16.3 fails to escape customer, project, and activity names in JavaScript, enabling stored XSS attacks.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Kimai2 before 1.16.3 fails to escape customer, project, and activity names in JavaScript, enabling stored XSS attacks.

Vulnerability

Kimai2 versions prior to 1.16.3 are vulnerable to stored cross-site scripting (XSS) due to improper neutralization of user-controlled input when rendering customer, project, and activity names in JavaScript templates. The KimaiRecentActivities plugin used replace() with plain string substitution for %customer%, %project%, and %activity% placeholders, allowing injected HTML/JavaScript to be executed in the browser of any user viewing the recent activities panel. The fix introduced in commit 89bfa82c61da0d3639e4038e689e25467baac8a0 and released in version 1.16.3 adds an escape() method that encodes &, <, and > characters. The vulnerable code path exists in js-src/plugin/KimaiRecentActivities.js (renamed in the commit). Affected versions: all Kimai2 releases before 1.16.3 [1][3][4].

Exploitation

An attacker with the ability to create or edit customers, projects, or activities can inject malicious JavaScript as the name of one of these entities. No special network position is required; the attacker only needs permission to create or modify those records (e.g., a user with customer management rights). When any user loads the page that displays recent activities, the unsanitized name is inserted into the DOM via JavaScript, causing the injected script to execute. The attack is stored and can affect all users who view the recent activities, including administrators [1][3][4].

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the victim’s session. This can lead to session hijacking, defacement, theft of sensitive data displayed in the application, or further actions performed as the victim user. The scope is within the browser session; the attacker gains the same privileges as the victim. Confidentiality, integrity, and availability of the application’s data may be compromised [1][3].

Mitigation

The vulnerability is fixed in Kimai2 version 1.16.3, released on 2021-11-30 [4]. Users should upgrade to 1.16.3 or later immediately. There is no known workaround short of restricting user permissions to prevent unauthorized entity creation, which does not eliminate the risk from existing malicious names. The fix ensures that customer, project, and activity names are properly HTML-escaped before insertion into the DOM [3][4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
kevinpapst/kimai2Packagist
< 1.16.31.16.3

Affected products

2

Patches

1
89bfa82c61da

escape customer, project and activity name in javascript (#2959)

https://github.com/kevinpapst/kimai2Kevin PapstNov 19, 2021via ghsa
7 files changed · +23 7
  • assets/js/KimaiPlugin.js+15 0 modified
    @@ -66,4 +66,19 @@ export default class KimaiPlugin {
             return this.getContainer().getPlugin(name);
         }
     
    +    /**
    +     * @param {string} title
    +     * @returns {string}
    +     */
    +    escape(title) {
    +        const tagsToReplace = {
    +            '&': '&amp;',
    +            '<': '&lt;',
    +            '>': '&gt;',
    +        };
    +
    +        return title.replace(/[&<>]/g, function(tag) {
    +            return tagsToReplace[tag] || tag;
    +        });
    +    };
     }
    
  • assets/js/plugins/KimaiRecentActivities.js+4 3 modified
    @@ -65,9 +65,10 @@ export default class KimaiRecentActivities extends KimaiPlugin {
     
             for (let timesheet of entries) {
                 let label = this.attributes['template']
    -                .replace('%customer%', timesheet.project.customer.name)
    -                .replace('%project%', timesheet.project.name)
    -                .replace('%activity%', timesheet.activity.name);
    +                .replace('%customer%', this.escape(timesheet.project.customer.name))
    +                .replace('%project%', this.escape(timesheet.project.name))
    +                .replace('%activity%', this.escape(timesheet.activity.name))
    +            ;
     
                 htmlToInsert +=
                     `<li>` +
    
  • public/build/app.3947eaef.js+0 2 removed
  • public/build/app.9e8f68cf.js+2 0 added
  • public/build/app.9e8f68cf.js.LICENSE.txt+0 0 renamed
  • public/build/entrypoints.json+1 1 modified
    @@ -3,7 +3,7 @@
         "app": {
           "js": [
             "build/runtime.b8e7bb04.js",
    -        "build/app.3947eaef.js"
    +        "build/app.9e8f68cf.js"
           ],
           "css": [
             "build/app.3bc2b4d9.css"
    
  • public/build/manifest.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "build/app.css": "build/app.3bc2b4d9.css",
    -  "build/app.js": "build/app.3947eaef.js",
    +  "build/app.js": "build/app.9e8f68cf.js",
       "build/invoice.css": "build/invoice.ff32661a.css",
       "build/invoice.js": "build/invoice.19f36eca.js",
       "build/invoice-pdf.css": "build/invoice-pdf.9a7468ef.css",
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.