CVE-2021-43851: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: Anuko Time Tracker is an open source, web-based time tracking application written in PHP. SQL injection vulnerability exist in multiple files in Time Tracker version 1.19.33.5606 and prior due to not properly checking of the "group" and "status" parameters in POST requests. Group parameter is posted along when navigating between organizational subgroups (groups.php file). Status parameter is used in multiple files to change a status of an entity such as making a project, task, or user inactive. This issue has been patched in version 1.19.33.5607. An upgrade is highly recommended. If an upgrade is not practical, introduce ttValidStatus function as in the latest version and start using it user input check blocks wherever status field is used. For groups.php fix, introduce ttValidInteger function as in the latest version and use it in the access check block in the file.
CWE description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
CVSS v3 base score: 8.8
Published: 2021-12-22T00:15Z
Repository: https://github.com/anuko/timetracker
Language: PHP
Files changed: groups.php, initialize.php
Commit date: 2021-10-20 20:51:47 +0000
Commit message: Fixed an sql injection vulnerability in groups.php.

Diff: diff --git a/groups.php b/groups.php
index a7bf2dfe6..ca01a5f7c 100644
--- a/groups.php
+++ b/groups.php
@@ -9,13 +9,20 @@ import('form.Form');
 // Access checks.
 if (!ttAccessAllowed('manage_subgroups')) {
   header('Location: access_denied.php');
   exit();
 }
-if ($request->isPost() && !$user->isGroupValid($request->getParameter('group'))) {
-  header('Location: access_denied.php'); // Wrong group id in post.
-  exit();
+if ($request->isPost()) {
+  $group_id = $request->getParameter('group');
+  if (!ttValidInteger($group_id)) {
+    header('Location: access_denied.php'); // Protection against sql injection.
+    exit();
+  }
+  if (!$user->isGroupValid($group_id)) {
+    header('Location: access_denied.php'); // Wrong group id in post.
+    exit();
+  }
 }
 // End of access checks.
 
 if ($request->isPost()) {
   $group_id = (int)$request->getParameter('group');
diff --git a/initialize.php b/initialize.php
index 63ee048df..92c907f30 100644
--- a/initialize.php
+++ b/initialize.php
@@ -10,11 +10,11 @@ error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT); // & ~E_DEPRECATED);
 // E_ALL tends to change as PHP evolves, therefore we use & here instead of exclusive OR (^).
 
 // Disable displaying errors on screen.
 ini_set('display_errors', 'Off');
 
-define("APP_VERSION", "1.19.30.5601");
+define("APP_VERSION", "1.19.31.5602");
 define("APP_DIR", dirname(__FILE__));
 define("LIBRARY_DIR", APP_DIR."/WEB-INF/lib");
 define("TEMPLATE_DIR", APP_DIR."/WEB-INF/templates");
 // Date format for database and URI parameters.
 define('DB_DATEFORMAT', '%Y-%m-%d');

Vulnerable code: if ($request->isPost() && !$user->isGroupValid($request->getParameter('group'))) {
  header('Location: access_denied.php'); // Wrong group id in post.
  exit();
define("APP_VERSION", "1.19.30.5601");
Fixed code: if ($request->isPost()) {
  $group_id = $request->getParameter('group');
  if (!ttValidInteger($group_id)) {
    header('Location: access_denied.php'); // Protection against sql injection.
    exit();
  }
  if (!$user->isGroupValid($group_id)) {
    header('Location: access_denied.php'); // Wrong group id in post.
    exit();
  }
define("APP_VERSION", "1.19.31.5602");