CVE-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
⚡ Watch CVE-2026-52820
Get an email if CVE-2026-52820 is added to CISA KEV, gains public exploit code, or a new advisory cites it — max one per day, one-click unsubscribe.
Advisory coverage (1)
External references
Embed the live status
— this badge updates automatically when the KEV or exploit status changes. How to embed it →
[](https://www.csirts.com/cve/CVE-2026-52820)