CVE-2022-1825: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Reflected in GitHub repository collectiveaccess/providence prior to 1.8.
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: 5.4
Published: 2022-05-23T11:16Z
Repository: https://github.com/collectiveaccess/providence
Language: PHP
Files changed: app/controllers/system/ErrorController.php, app/lib/ApplicationError.php, app/lib/Controller/Request/RequestHTTP.php
Commit date: 2022-04-30 10:25:48 -0400
Commit message: Print potential XSS in error message handler

Diff: diff --git a/app/controllers/system/ErrorController.php b/app/controllers/system/ErrorController.php
index 00de38abe..d37c64b33 100644
--- a/app/controllers/system/ErrorController.php
+++ b/app/controllers/system/ErrorController.php
@@ -27,12 +27,10 @@
  */
 
 require_once(__CA_LIB_DIR__."/ApplicationError.php");
 
 class ErrorController extends ActionController {
-	# -------------------------------------------------------
-	
 	# -------------------------------------------------------
 	function Show() {
 		$o_purify = caGetHTMLPurifier();
 		
 		$va_nums = explode(';', $this->request->getParameter('n', pString));
diff --git a/app/lib/ApplicationError.php b/app/lib/ApplicationError.php
index 505debc33..629b4a673 100755
--- a/app/lib/ApplicationError.php
+++ b/app/lib/ApplicationError.php
@@ -173,11 +173,11 @@ class ApplicationError {
  * @param string $ps_error_context Context where error occurred. This is typically the Class name and method name where the error occurred. Ex. "Configuration->new()"
  * @param string $ps_error_source Source of error - typically a string identifying the field in a form where the error occurred.
  * @return integer Always returns 1
  */		
 	public function setError ($pn_error_number, $ps_error_description='', $ps_error_context='', $ps_error_source='') {
-		$this->opn_error_number = $pn_error_number;
+		$this->opn_error_number = (int)$pn_error_number;
 		$this->ops_error_description = $ps_error_description;
 		$this->ops_error_context = $ps_error_context;
 		$this->ops_error_source = $ps_error_source;
 		
 		if (($this->opb_halt_on_error) || ($this->opb_report_on_error)) {
@@ -319,11 +319,11 @@ class ApplicationError {
 	public function getErrorMessage() {
 		$vs_error_message = $this->opo_error_messages->get($this->opn_error_number);
 		if ($vs_error_message) {
 			return $vs_error_message;
 		} else {
-			return "Unknown error: ".$this->opn_error_number;
+			return "Unknown error: ".(int)$this->opn_error_number;
 		}
 	}
 	
 /**
  * Returns the source of the current error.
diff --git a/app/lib/Controller/Request/RequestHTTP.php b/app/lib/Controller/Request/RequestHTTP.php
index 088500609..dc10a4643 100644
--- a/app/lib/Controller/Request/RequestHTTP.php
+++ b/app/lib/Controller/Request/RequestHTTP.php
@@ -574,16 +574,19 @@ class RequestHTTP extends Request {
 	public function getParameter($pa_name, $pn_type, $ps_http_method=null, $pa_options=array()) {
 		$vm_val = $this->parameterExists($pa_name, $ps_http_method, $pa_options);
 		if (!isset($vm_val)) { return ""; }
 		
 		$vm_val = str_replace("\0", '', $vm_val);
+		
+		$purified = false;
 		if((caGetOption('purify', $pa_options, true) && $this->config->get('purify_all_text_input')) || caGetOption('forcePurify', $pa_options, false)) {
 		    if(is_array($vm_val)) {
 		        $vm_val = array_map(function($v) { return is_array($v) ? $v : str_replace("&amp;", "&", RequestHTTP::getPurifier()->purify(rawurldecode($v))); }, $vm_val);
 		    } else {
 		        $vm_val = str_replace("&amp;", "&", RequestHTTP::getPurifier()->purify(rawurldecode($vm_val)));
 		    }
+		    $purified = true;
 		}
 		
 		if ($vm_val == "") { return ($pn_type == pArray) ? [] : ''; }
 		
 		switch($pn_type) {
@@ -605,11 +608,11 @@ class RequestHTTP extends Request {
 			case pString:
 				if (is_string($vm_val)) {
 					if(caGetOption('retainBackslashes', $pa_options, true)) {
 						$vm_val = str_replace("\\", "\\\\", $vm_val);	// retain backslashes for some strange people desire them as valid input
 					}
-					if(caGetOption('urldecode', $pa_options, true)) {
+					if(!$purified && caGetOption('urldecode', $pa_options, true)) {
 						$vm_val = rawurldecode($vm_val);
 					}
 					return $vm_val;
 				}
 				break;

Vulnerable code: 	# -------------------------------------------------------
	
		$this->opn_error_number = $pn_error_number;
			return "Unknown error: ".$this->opn_error_number;
					if(caGetOption('urldecode', $pa_options, true)) {
Fixed code: 		$this->opn_error_number = (int)$pn_error_number;
			return "Unknown error: ".(int)$this->opn_error_number;
		
		$purified = false;
		    $purified = true;
					if(!$purified && caGetOption('urldecode', $pa_options, true)) {