CVE-2021-4033 (published 2021-12-09T20:15Z)

kimai2 is vulnerable to Cross-Site Request Forgery (CSRF)

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:P/A:N)
CVSS v3 base score: 6.5, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N)

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/kevinpapst/kimai2
commit_details: repo_url: https://github.com/kevinpapst/kimai2
author: Kevin Papst
author_date: 2021-12-04 01:18:49+01:00
msg: fix invoice create and search (#2990)
repository: repo_url: https://github.com/kevinpapst/kimai2
repo_name: kimai/kimai
description: Kimai is a web-based multi-user time-tracking application. Works great for everyone: freelancers, companies, organizations - everyone can track their times, generate reports, create invoices and do so much more. SaaS version available at https://www.kimai.cloud
repo_language: PHP
owner: kevinpapst
file_changes: filename: AbstractController.php
change_type: ModificationType.MODIFY
diff: @@ -218,6 +218,8 @@ abstract class AbstractController extends BaseAbstractController implements Serv
             }
         }
 
+        $request->query->remove('_token');
+
         if ($request->query->has('resetSearchFilter')) {
             $data->resetFilter();
             $this->removeLastSearch($data);

programming_language: PHP
filename: InvoiceController.php
change_type: ModificationType.MODIFY
diff: @@ -66,7 +66,7 @@ final class InvoiceController extends AbstractController
      * @Route(path="/", name="invoice", methods={"GET", "POST"})
      * @Security("is_granted('view_invoice')")
      */
-    public function indexAction(Request $request, SystemConfiguration $configuration): Response
+    public function indexAction(Request $request, SystemConfiguration $configuration, CsrfTokenManagerInterface $csrfTokenManager): Response
     {
         if (!$this->templateRepository->hasTemplate()) {
             if ($this->isGranted('manage_invoice_template')) {
@@ -100,6 +100,8 @@ final class InvoiceController extends AbstractController
                     return $this->redirectToRoute('invoice');
                 }
 
+                $csrfTokenManager->refreshToken('invoice.create');
+
                 try {
                     return $this->renderInvoice($query, $request);
                 } catch (Exception $ex) {
@@ -148,6 +150,7 @@ final class InvoiceController extends AbstractController
 
         if ($form->isValid()) {
             try {
+                $query->setCustomers([$customer]);
                 $model = $this->service->createModel($query);
 
                 return $this->service->renderInvoiceWithModel($model, $this->dispatcher);
@@ -167,7 +170,7 @@ final class InvoiceController extends AbstractController
      * @Security("is_granted('access', customer)")
      * @Security("is_granted('create_invoice')")
      */
-    public function createInvoiceAction(Customer $customer, InvoiceTemplate $template, Request $request, SystemConfiguration $configuration): Response
+    public function createInvoiceAction(Customer $customer, InvoiceTemplate $template, Request $request, SystemConfiguration $configuration, CsrfTokenManagerInterface $csrfTokenManager): Response
     {
         if (!$this->templateRepository->hasTemplate()) {
             return $this->redirectToRoute('invoice');
@@ -185,9 +188,13 @@ final class InvoiceController extends AbstractController
             return $this->redirectToRoute('invoice');
         }
 
+        $csrfTokenManager->refreshToken('invoice.create');
+
         $query = $this->getDefaultQuery();
         $form = $this->getToolbarForm($query, $configuration->find('invoice.simple_form'));
-        $form->submit($request->query->all(), false);
+        if ($this->handleSearch($form, $request)) {
+            return $this->redirectToRoute('invoice');
+        }
 
         if ($form->isValid()) {
             $query->setTemplate($template);

programming_language: PHP
filename: SelectWithApiDataExtension.php
change_type: ModificationType.MODIFY
diff: @@ -75,8 +75,12 @@ class SelectWithApiDataExtension extends AbstractTypeExtension
         } while (($parent = $parent->getParent()) !== null);
 
         $formPrefix = implode('_', array_reverse($formPrefixes));
+        $formField = $apiData['select'];
 
-        $formField = $formPrefix . '_' . $apiData['select'];
+        // forms with prefix (like toolbar & search) would result in a wrong field name "_foo" instead of "foo"
+        if ($formPrefix !== '') {
+            $formField = $formPrefix . '_' . $apiData['select'];
+        }
 
         $view->vars['attr'] = array_merge($view->vars['attr'], [
             'data-form-prefix' => $formPrefix,

programming_language: PHP