CVE-2021-41139: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Anuko Time Tracker is an open source, web-based time tracking application written in PHP. When a logged on user selects a date in Time Tracker, it is being passed on via the date parameter in URI. Because of not checking this parameter for sanity in versions prior to 1.19.30.5600, it was possible to craft the URI with malicious JavaScript, use social engineering to convince logged on user to click on such link, and have the attacker-supplied JavaScript to be executed in user's browser. This issue is patched in version 1.19.30.5600. As a workaround, one may introduce `ttValidDbDateFormatDate` function as in the latest version and add a call to it within the access checks block in time.php.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2021-10-13T17:15Z
Repository: https://github.com/anuko/timetracker
Language: PHP
Files changed: WEB-INF/lib/common.lib.php, initialize.php, time.php
Commit date: 2021-10-12 20:31:02 +0000
Commit message: A better fix to validate a passed-in date.

Diff: diff --git a/WEB-INF/lib/common.lib.php b/WEB-INF/lib/common.lib.php
index d5b43f57f..db8d58ea3 100644
--- a/WEB-INF/lib/common.lib.php
+++ b/WEB-INF/lib/common.lib.php
@@ -224,19 +224,33 @@ function ttValidDate($val)
 {
   $val = trim($val);
   if (strlen($val) == 0)
     return false;
 
-  // This should accept a string in format 'YYYY-MM-DD', 'MM/DD/YYYY', 'DD-MM-YYYY', 'DD.MM.YYYY', or 'DD.MM.YYYY whatever'.
+  // This should validate a string in format 'YYYY-MM-DD', 'MM/DD/YYYY', 'DD-MM-YYYY', 'DD.MM.YYYY', or 'DD.MM.YYYY whatever'.
   if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $val) &&
     !preg_match('/^\d\d\/\d\d\/\d\d\d\d$/', $val) &&
     !preg_match('/^\d\d\-\d\d\-\d\d\d\d$/', $val) &&
     !preg_match('/^\d\d\.\d\d\.\d\d\d\d$/', $val) &&
     !preg_match('/^\d\d\.\d\d\.\d\d\d\d .+$/', $val))
     return false;
-    
-  return true;    
+
+  return true;
+}
+
+// ttValidDbDateFormatDate is used to check user input to validate a date in DB_DATEFORMAT.
+function ttValidDbDateFormatDate($val)
+{
+  $val = trim($val);
+  if (strlen($val) == 0)
+    return false;
+
+  // This should validate a string in format 'YYYY-MM-DD'.
+  if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $val))
+    return false;
+
+  return true;
 }
 
 // ttValidInteger is used to check user input to validate an integer.
 function ttValidInteger($val, $emptyValid = false)
 {
diff --git a/initialize.php b/initialize.php
index e0b38f4d5..3d6aeab4c 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.5599");
+define("APP_VERSION", "1.19.30.5600");
 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');
diff --git a/time.php b/time.php
index 61e771f8b..e5e509c06 100644
--- a/time.php
+++ b/time.php
@@ -32,11 +32,11 @@ if ($request->isPost()) {
     exit();
   }
 }
 // If we are passed in a date, make sure it is in correct format.
 $date = $request->getParameter('date');
-if ($date && !ttValidDate($date)) {
+if ($date && !ttValidDbDateFormatDate($date)) {
   header('Location: access_denied.php');
   exit();
 }
 // End of access checks.
 

Vulnerable code:   // This should accept a string in format 'YYYY-MM-DD', 'MM/DD/YYYY', 'DD-MM-YYYY', 'DD.MM.YYYY', or 'DD.MM.YYYY whatever'.
    
  return true;    
define("APP_VERSION", "1.19.30.5599");
if ($date && !ttValidDate($date)) {
Fixed code:   // This should validate a string in format 'YYYY-MM-DD', 'MM/DD/YYYY', 'DD-MM-YYYY', 'DD.MM.YYYY', or 'DD.MM.YYYY whatever'.

  return true;
}

// ttValidDbDateFormatDate is used to check user input to validate a date in DB_DATEFORMAT.
function ttValidDbDateFormatDate($val)
{
  $val = trim($val);
  if (strlen($val) == 0)
    return false;

  // This should validate a string in format 'YYYY-MM-DD'.
  if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $val))
    return false;

  return true;
define("APP_VERSION", "1.19.30.5600");
if ($date && !ttValidDbDateFormatDate($date)) {