GHSA-9g2q-w3w2-vf7q

Suggest an improvement
Source
https://github.com/advisories/GHSA-9g2q-w3w2-vf7q
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-9g2q-w3w2-vf7q/GHSA-9g2q-w3w2-vf7q.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-9g2q-w3w2-vf7q
Aliases
Published
2026-05-06T18:28:45Z
Modified
2026-08-27T04:10:44Z
Severity
  • 5.7 (Medium) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P CVSS Calculator
Summary
Kimai has Missing Voter Check that Allows Cross-Team Timesheet Manipulation
Details

Summary

Any ROLE_TEAMLEAD user can enumerate, read, modify, and permanently delete timesheets belonging to any other user in the system — regardless of team membership. This enables data destruction (deleted billable hours), data tampering (forged timesheet durations), and full authorization bypass on timesheet resources. Verified against Kimai 2.52.0.

Details

TimesheetVoter::voteOnAttribute() maps permissions to own_timesheet or other_timesheet without checking team membership. The voter's own comment confirms this is a known gap:

// extend me for "team" support later on
if ($subject->getUser()?->getId() === $user->getId()) {
    $permission .= 'own';
} else {
    $permission .= 'other';
}

PoC

Tested against Kimai 2.52.0 Docker instance.

Setup:

  • User A (usera, ROLE_TEAMLEAD) owns timesheet ID 2 with description "Private timesheet - UserA only"
  • User B (userb, ROLE_TEAMLEAD) is NOT on any team with User A

User B reads User A's timesheet data:

GET /api/timesheets/2 HTTP/1.1
X-AUTH-USER: userb
X-AUTH-TOKEN: <userb_api_token>

Response: HTTP 200 — returns full timesheet record including description "Private timesheet - UserA only".

User B deletes User A's timesheet:

DELETE /api/timesheets/3 HTTP/1.1
X-AUTH-USER: userb
X-AUTH-TOKEN: <userb_api_token>

Response: HTTP 204 No Content — timesheet permanently deleted.

User B tampers User A's timesheet:

PATCH /api/timesheets/6 HTTP/1.1
X-AUTH-USER: userb
X-AUTH-TOKEN: <userb_api_token>
Content-Type: application/json

{"begin":"2026-03-24T08:00:00","end":"2026-03-24T18:00:00","project":1,"activity":1,"description":"TAMPERED","exported":false,"billable":false}

Response: HTTP 200 OK — duration inflated from 3600s to 36000s, description overwritten.

Note: ROLE_USER (userc) is correctly blocked — DELETE returns 403 and the actions endpoint returns an empty array. The vulnerability only affects ROLE_TEAMLEAD and above. Timesheet IDs are sequential integers, trivially enumerable.

Impact

Any authenticated user with ROLE_TEAMLEAD or above can:

  1. Permanently delete timesheets belonging to any user system-wide — destroying billable hours, payroll data, and project billing history
  2. Silently alter timesheet descriptions, hours, and billing flags — forging hours up or down, directly affecting invoicing and payroll
  3. Enumerate all timesheet IDs (sequential integers) and access action metadata for arbitrary records

No user interaction required. ROLE_USER accounts are correctly restricted; the vulnerability is specific to ROLE_TEAMLEAD receiving global scope instead of team-scoped access.

Maintainers answer: why this is not eligible for a CVE

The behavior described matches the documented permission model. Per the Kimai documentation, the relevant permissions granted to ROLE_TEAMLEAD are:

  • edit_other_timesheet — Edit existing records of other users
  • delete_other_timesheet — Delete existing records of other users

These permissions were global by design, not team-scoped. The UI surfaces only the teamlead's own team timesheets, but the API has historically honored these permissions as documented: a role holding *_other_timesheet can act on any other user's timesheet. The inline comment // extend me for "team" support later on reflects this accurately — team-scoped enforcement was a planned enhancement, not a security control that existed and failed.

The report frames this as authorization bypass, but no authorization boundary is being crossed: ROLE_TEAMLEAD is operating within its documented permissions.

Kimai acknowledges that this behavior might not be expected, so while it will be treated as a feature request for team-scoped permission enforcement and not a vulnerability, it still track it as having security implications.

Solution

Team-scoped timesheet permission checks were added in 2.56.0.

Operators of Kimai <= 2.55 who need stricter isolation between teamleads should not grant ROLE_TEAMLEAD to users who must not act on other teams' timesheets.

Database specific
{
    "cwe_ids":  [
        "CWE-863"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-05-06T18:28:45Z",
    "nvd_published_at":  null,
    "severity":  "MODERATE"
}
References

Affected packages

Packagist / kimai/kimai

Package

Name
kimai/kimai
Purl
pkg:composer/kimai/kimai

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
2.56.0

Affected versions

0.*
0.1
0.2
0.3
0.4
0.5
0.6
0.6.1
0.7
0.8
0.8.1
0.9
1.*
1.0
1.0.1
1.1
1.2
1.3
1.4
1.4.1
1.4.2
1.5
1.6
1.6.1
1.6.2
1.7
1.8
1.9
1.10
1.10.1
1.10.2
1.11
1.11.1
1.12
1.13
1.14
1.14.1
1.14.2
1.14.3
1.15
1.15.1
1.15.2
1.15.3
1.15.4
1.15.5
1.15.6
1.16
1.16.1
1.16.2
1.16.3
1.16.4
1.16.5
1.16.6
1.16.7
1.16.8
1.16.9
1.16.10
1.17
1.17.1
1.18
1.18.1
1.18.2
1.19
1.19.1
1.19.2
1.19.3
1.19.4
1.19.5
1.19.6
1.19.7
1.20
1.20.1
1.20.2
1.20.3
1.20.4
1.21.0
1.22.0
1.22.1
1.23.0
1.23.1
1.24.0
1.25.0
1.26.0
1.27.0
1.28.0
1.28.1
1.29.0
1.29.1
1.30.0
1.30.1
1.30.2
1.30.3
1.30.4
1.30.5
1.30.6
1.30.7
1.30.8
1.30.9
1.30.10
1.30.11
2.*
2.0.0-alpha
2.0.0-beta
2.0.0-beta-2
2.0.0-beta-3
2.0.0-rc-1
2.0.0
2.0.1
2.0.2
2.0.3
2.0.4
2.0.5
2.0.6
2.0.7
2.0.8
2.0.9
2.0.10
2.0.11
2.0.12
2.0.13
2.0.14
2.0.15
2.0.16
2.0.17
2.0.18
2.0.19
2.0.20
2.0.21
2.0.22
2.0.23
2.0.24
2.0.25
2.0.26
2.0.27
2.0.28
2.0.29
2.0.30
2.0.31
2.0.32
2.0.33
2.0.34
2.0.35
2.1.0
2.2.0
2.2.1
2.3.0
2.4.0
2.4.1
2.5.0
2.6.0
2.7.0
2.8.0
2.9.0
2.10.0
2.11.0
2.12.0
2.13.0
2.14.0
2.15.0
2.16.0
2.16.1
2.17.0
2.18.0
2.19.0
2.19.1
2.20.0
2.20.1
2.21.0
2.22.0
2.23.0
2.24.0
2.25.0
2.26.0
2.27.0
2.28.0
2.29.0
2.30.0
2.31.0
2.32.0
2.33.0
2.34.0
2.35.0
2.35.1
2.36.0
2.36.1
2.37.0
2.38.0
2.39.0
2.40.0
2.41.0
2.42.0
2.43.0
2.44.0
2.45.0
2.46.0
2.47.0
2.48.0
2.49.0
2.50.0
2.51.0
2.52.0
2.53.0
2.54.0
2.55.0

Database specific

last_known_affected_version_range
"<= 2.55.0"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-9g2q-w3w2-vf7q/GHSA-9g2q-w3w2-vf7q.json"