CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-vrr2-g9gh-c3jc: Kimai: Timesheet PATCH/POST allows assigning to project outside user's team via query_builder OR-bypass

mediumCVE-2026-52820
Summary The Timesheet API PATCH /api/timesheets/{id} and POST /api/timesheets endpoints accept a user-supplied project ID and resolve it through a Symfony EntityType whose query_builder allows the submitted ID to satisfy the access predicate via an unconditional OR branch. As a result, any authenticated user can re-assign their own timesheet to any project in the database — including projects that belong to teams or customers they have no membership in and cannot otherwise see. The user can then read serialized project/customer details via GET /api/timesheets/{id}?full=true, leaking metadata (name, currency, customer hierarchy) that would otherwise be filtered out by the team ACL. Details Entry point — only ownership is checked in src/API/TimesheetController.php:317-355 #[IsGranted('edit', 'timesheet')] #[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_timesheet', requirements: ['id' => '\d+'])] public function patchAction(Request $request, Timesheet $timesheet): Response { ... $form = $this->createForm(TimesheetApiEditForm::class, $timesheet, [...]); $form->setData($timesheet); $form->submit($request->request->all(), false); if (false === $form->isValid()) { ... } $this->service->saveTimesheet($timesheet); ... } src/Voter/TimesheetVoter.php:134-142: if ($subject->getUser()?->getId() === $user->getId()) { return $this->permissionManager->hasRolePermission($user, $permission . '_own_timesheet'); } if (!$this->permissionManager->checkTeamAccessTimesheet($subject, $user)) { return false; } For an own-timesheet, only edit_own_timesheet is required. The voter does not look at the *new* project being submitted; it only validates the existing record's ownership. Form replays user-controlled project ID into the access query src/Form/TimesheetEditForm.php:60-71: $isNew = true; if (isset($options['data']) && $options['data'] instanceof Timesheet) { ... if (null !== $entry->getId()) { $isNew = false; } ... } $this->addProject($builder, $isNew, $project, $custo

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
medium
Published
2026-07-13
Last updated
2026-07-13
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-vrr2-g9gh-c3jc

Referenced CVEs

CVECSIRTS overviewExternal
CVE-2026-52820coverage & exploitation statusNVD · CVE.org

More from GitHub Security Advisories