CVE-2022-31889: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross Site Scripting (XSS) vulnerability in audit/templates/auditlogs.tmpl.php in osTicket osTicket-plugins before commit a7842d494889fd5533d13deb3c6a7789768795ae.
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: 2023-04-05T22:15Z
Repository: https://github.com/osTicket/osTicket-plugins
Language: PHP
Files changed: audit/templates/auditlogs.tmpl.php
Commit date: 2022-04-21 18:52:58 +0000
Commit message: xss: Audit Log

This mitigates a vulnerability discovered by the AppSec Research Team at
Checkmarx where it's possible to perform XSS via the Audit Log plugin. This
is due to not properly escaping the `state` and `type` URL params. This adds
`Format::htmlchars()` to both params to ensure they are properly escaped.

Diff: diff --git a/audit/templates/auditlogs.tmpl.php b/audit/templates/auditlogs.tmpl.php
index df795a7..78b697f 100644
--- a/audit/templates/auditlogs.tmpl.php
+++ b/audit/templates/auditlogs.tmpl.php
@@ -1,22 +1,22 @@
 <?php
 if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
 
 $qs = array();
 if($_REQUEST['type'])
-    $qs += array('type' => $_REQUEST['type']);
+    $qs += array('type' => Format::htmlchars($_REQUEST['type']));
 $type='D';
 
 if ($_REQUEST['type'])
-  $type=$_REQUEST['type'];
+  $type=Format::htmlchars($_REQUEST['type']);
 
 if($_REQUEST['state'])
-    $qs += array('state' => $_REQUEST['state']);
+    $qs += array('state' => Format::htmlchars($_REQUEST['state']));
 $state=__('All');
 
 if ($_REQUEST['state'])
-  $state=$_REQUEST['state'];
+  $state=Format::htmlchars($_REQUEST['state']);
 
 //dates
 $startTime  =($_REQUEST['startDate'] && (strlen($_REQUEST['startDate'])>=8))?strtotime($_REQUEST['startDate']):0;
 $endTime    =($_REQUEST['endDate'] && (strlen($_REQUEST['endDate'])>=8))?strtotime($_REQUEST['endDate']):0;
 if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)){
@@ -26,11 +26,11 @@ if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)){
     if($startTime)
         $qs += array('startDate' => $_REQUEST['startDate']);
     if($endTime)
         $qs += array('endDate' => $_REQUEST['endDate']);
 }
-$order = AuditEntry::getOrder($_REQUEST['order']);
+$order = AuditEntry::getOrder(Format::htmlchars($_REQUEST['order']));
 $qs += array('order' => (($order=='DESC') ? 'ASC' : 'DESC'));
 $qstr = '&amp;'. Http::build_query($qs);
 
 $args = array();
 parse_str($_SERVER['QUERY_STRING'], $args);

Vulnerable code:     $qs += array('type' => $_REQUEST['type']);
  $type=$_REQUEST['type'];
    $qs += array('state' => $_REQUEST['state']);
  $state=$_REQUEST['state'];
$order = AuditEntry::getOrder($_REQUEST['order']);
Fixed code:     $qs += array('type' => Format::htmlchars($_REQUEST['type']));
  $type=Format::htmlchars($_REQUEST['type']);
    $qs += array('state' => Format::htmlchars($_REQUEST['state']));
  $state=Format::htmlchars($_REQUEST['state']);
$order = AuditEntry::getOrder(Format::htmlchars($_REQUEST['order']));