VYPR
Unrated severityNVD Advisory· Published Oct 21, 2019· Updated Aug 5, 2024

CVE-2019-16980

CVE-2019-16980

Description

In FusionPBX up to v4.5.7, the file app\call_broadcast\call_broadcast_edit.php uses an unsanitized "id" variable coming from the URL in an unparameterized SQL query, leading to SQL injection.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

FusionPBX up to v4.5.7 has a SQL injection in call_broadcast_edit.php via unsanitized 'id' parameter.

Vulnerability

In FusionPBX up to v4.5.7, the file app\call_broadcast\call_broadcast_edit.php uses an unsanitized id variable from the URL in an unparameterized SQL query, leading to SQL injection [1][2]. The vulnerable code does not validate that the id is a UUID. Affected versions include all prior to the fix.

Exploitation

An authenticated user can exploit this by sending a crafted HTTP GET request with a malicious id parameter to the endpoint [2]. No additional privileges beyond authentication are required.

Impact

Successful exploitation allows an authenticated attacker to execute arbitrary SQL commands, potentially accessing, modifying, or deleting data in the FusionPBX database, such as user credentials and configuration [2].

Mitigation

The vulnerability was fixed in commit 6fe372b on June 8, 2019 [1]. Users should upgrade to a version including this fix or apply the patch manually. The fix adds an is_uuid check to ensure the id is a valid UUID.

AI Insight generated on May 26, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

1
6fe372b3d4bb

Call Broadcast: Database class integration.

4 files changed · +143 182
  • app/call_broadcast/call_broadcast_delete.php+0 1 modified
    @@ -48,7 +48,6 @@
     		$database->app_name = 'call_broadcasts';
     		$database->app_uuid = 'efc11f6b-ed73-9955-4d4d-3a1bed75a056';
     		$database->delete($array);
    -		$response = $database->message;
     		unset($array);
     
     		message::add($text['message-delete']);
    
  • app/call_broadcast/call_broadcast_edit.php+120 163 modified
    @@ -44,16 +44,16 @@
     	$text = $language->get();
     
     //set the action with add or update
    -	if (isset($_REQUEST["id"])) {
    +	if (is_uuid($_REQUEST["id"])) {
     		$action = "update";
    -		$call_broadcast_uuid = check_str($_REQUEST["id"]);
    +		$call_broadcast_uuid = $_REQUEST["id"];
     	}
     	else {
     		$action = "add";
     	}
     
     //function to Upload CSV/TXT file
    -	function upload_file($sql,$broadcast_phone_numbers) {
    +	function upload_file($sql, $broadcast_phone_numbers) {
     		$upload_csv = $sql = '';
     		if (isset($_FILES['broadcast_phone_numbers_file']) && !empty($_FILES['broadcast_phone_numbers_file']) && $_FILES['broadcast_phone_numbers_file']['size'] > 0) {
     			$filename=$_FILES["broadcast_phone_numbers_file"]["tmp_name"];
    @@ -94,33 +94,32 @@ function upload_file($sql,$broadcast_phone_numbers) {
     
     //get the http post variables and set them to php variables
     	if (count($_POST)>0) {
    -		$broadcast_name = check_str($_POST["broadcast_name"]);
    -		$broadcast_description = check_str($_POST["broadcast_description"]);
    -		$broadcast_timeout = check_str($_POST["broadcast_timeout"]);
    -		$broadcast_concurrent_limit = check_str($_POST["broadcast_concurrent_limit"]);
    -		//$recording_uuid = check_str($_POST["recording_uuid"]);
    -		$broadcast_caller_id_name = check_str($_POST["broadcast_caller_id_name"]);
    -		$broadcast_caller_id_number = check_str($_POST["broadcast_caller_id_number"]);
    -		$broadcast_destination_type = check_str($_POST["broadcast_destination_type"]);
    -		$broadcast_phone_numbers = check_str($_POST["broadcast_phone_numbers"]);
    -		$broadcast_avmd = check_str($_POST["broadcast_avmd"]);
    -		$broadcast_destination_data = check_str($_POST["broadcast_destination_data"]);
    +		$broadcast_name = $_POST["broadcast_name"];
    +		$broadcast_description = $_POST["broadcast_description"];
    +		$broadcast_timeout = $_POST["broadcast_timeout"];
    +		$broadcast_concurrent_limit = $_POST["broadcast_concurrent_limit"];
    +		//$recording_uuid = $_POST["recording_uuid"];
    +		$broadcast_caller_id_name = $_POST["broadcast_caller_id_name"];
    +		$broadcast_caller_id_number = $_POST["broadcast_caller_id_number"];
    +		$broadcast_destination_type = $_POST["broadcast_destination_type"];
    +		$broadcast_phone_numbers = $_POST["broadcast_phone_numbers"];
    +		$broadcast_avmd = $_POST["broadcast_avmd"];
    +		$broadcast_destination_data = $_POST["broadcast_destination_data"];
     
     		if (if_group("superadmin")){
    -			$broadcast_accountcode = check_str($_POST["broadcast_accountcode"]);
    +			$broadcast_accountcode = $_POST["broadcast_accountcode"])
     		}
    -		elseif (if_group("admin") && file_exists($_SERVER["PROJECT_ROOT"]."/app/billing/app_config.php")){
    -			$sql_accountcode = "SELECT COUNT(*) as count FROM v_billings WHERE domain_uuid = '".$_SESSION['domain_uuid']."' AND type_value='".$_POST["accountcode"]."'";
    -			$prep_statement_accountcode = $db->prepare(check_sql($sql_accountcode));
    -			$prep_statement_accountcode->execute();
    -			$row_accountcode = $prep_statement_accountcode->fetch(PDO::FETCH_ASSOC);
    -			if ($row_accountcode['count'] > 0) {
    -				$broadcast_accountcode = check_str($_POST["broadcast_accountcode"]);
    -			}
    -			else {
    -				$broadcast_accountcode = $_SESSION['domain_name'];
    -			}
    -			unset($sql_accountcode, $prep_statement_accountcode, $row_accountcode);
    +		else if (if_group("admin") && file_exists($_SERVER["PROJECT_ROOT"]."/app/billing/app_config.php")){
    +			$sql = "select count(*) ";
    +			$sql .= "from v_billings ";
    +			$sql .= "where domain_uuid = :domain_uuid ";
    +			$sql .= "and type_value = :type_value ";
    +			$parameters['domain_uuid'] = $_SESSION['domain_uuid'];
    +			$parameters['type_value'] = $_POST['accountcode'];
    +			$database = new database;
    +			$num_rows = $database->select($sql, $parameters, 'column');
    +			$broadcast_accountcode = $num_rows > 0 ? $_POST["broadcast_accountcode"] : $_SESSION['domain_name'];
    +			unset($sql, $parameters, $num_rows);
     		}
     		else{
     			$broadcast_accountcode = $_SESSION['domain_name'];
    @@ -131,7 +130,7 @@ function upload_file($sql,$broadcast_phone_numbers) {
     
     	$msg = '';
     	if ($action == "update") {
    -		$call_broadcast_uuid = check_str($_POST["call_broadcast_uuid"]);
    +		$call_broadcast_uuid = $_POST["call_broadcast_uuid"];
     	}
     
     	//check for all required data
    @@ -161,131 +160,87 @@ function upload_file($sql,$broadcast_phone_numbers) {
     
     	//add or update the database
     	if ($_POST["persistformvar"] != "true") {
    -		if ($action == "add" && permission_exists('call_broadcast_add')) {
    -			$call_broadcast_uuid = uuid();
    -			$sql = "insert into v_call_broadcasts ";
    -			$sql .= "(";
    -			$sql .= "domain_uuid, ";
    -			$sql .= "call_broadcast_uuid, ";
    -			$sql .= "broadcast_name, ";
    -			$sql .= "broadcast_description, ";
    -			$sql .= "broadcast_timeout, ";
    -			$sql .= "broadcast_concurrent_limit, ";
    -			//$sql .= "recording_uuid, ";
    -			$sql .= "broadcast_caller_id_name, ";
    -			$sql .= "broadcast_caller_id_number, ";
    -			$sql .= "broadcast_destination_type, ";
    -			$sql .= "broadcast_phone_numbers, ";
    -			$sql .= "broadcast_avmd, ";
    -			$sql .= "broadcast_destination_data, ";
    -			$sql .= "broadcast_accountcode ";
    -			$sql .= ")";
    -			$sql .= "values ";
    -			$sql .= "(";
    -			$sql .= "'$domain_uuid', ";
    -			$sql .= "'$call_broadcast_uuid', ";
    -			$sql .= "'$broadcast_name', ";
    -			$sql .= "'$broadcast_description', ";
    -			if (strlen($broadcast_timeout) == 0) {
    -				$sql .= "null, ";
    -			}
    -			else {
    -				$sql .= "'$broadcast_timeout', ";
    -			}
    -			if (strlen($broadcast_concurrent_limit) == 0) {
    -				$sql .= "null, ";
    -			}
    -			else {
    -				$sql .= "'$broadcast_concurrent_limit', ";
    -			}
    -			//$sql .= "'$recording_uuid', ";
    -			$sql .= "'$broadcast_caller_id_name', ";
    -			$sql .= "'$broadcast_caller_id_number', ";
    -			$sql .= "'$broadcast_destination_type', ";
    -
    -			//Add File selection and download sample 
    - 		        $file_res = upload_file($sql,$broadcast_phone_numbers);
    -			if ($file_res['code'] == true) {
    -				$sql .= $file_res['sql'];
    -			}
    -			else {
    -				$_SESSION["message_mood"] = "negative";
    -				$_SESSION["message"] = $text['file-error'];
    -				header("Location: call_broadcast_edit.php");
    -				return false;
    -			}
    -			
    -			$sql .= "'$broadcast_avmd', ";
    -			$sql .= "'$broadcast_destination_data', ";
    -			$sql .= "'$broadcast_accountcode' ";
    -			$sql .= ")";
    -			$db->exec(check_sql($sql));
    -			unset($sql);
    -
    -			message::add($text['confirm-add']);
    -			header("Location: call_broadcast.php");
    -			return;
    -		} //if ($action == "add")
    -
    -		if ($action == "update" && permission_exists('call_broadcast_edit')) {
    -			$sql = "update v_call_broadcasts set ";
    -			$sql .= "broadcast_name = '$broadcast_name', ";
    -			$sql .= "broadcast_description = '$broadcast_description', ";
    -			if (strlen($broadcast_timeout) == 0) {
    -				$sql .= "broadcast_timeout = null, ";
    -			}
    -			else {
    -				$sql .= "broadcast_timeout = '$broadcast_timeout', ";
    -			}
    -			if (strlen($broadcast_concurrent_limit) == 0) {
    -				$sql .= "broadcast_concurrent_limit = null, ";
    -			}
    -			else {
    -				$sql .= "broadcast_concurrent_limit = '$broadcast_concurrent_limit', ";
    +
    +		//prep insert
    +			if ($action == "add" && permission_exists('call_broadcast_add')) {
    +				//begin insert array
    +					$call_broadcast_uuid = uuid();
    +					$array['call_broadcasts'][0]['call_broadcast_uuid'] = $call_broadcast_uuid;
    +
    +				//set message
    +					message::add($text['confirm-add']);
    +
    +				//set return url on error
    +					$error_return_url = "call_broadcast_edit.php";
     			}
    -			//$sql .= "recording_uuid = '$recording_uuid', ";
    -			$sql .= "broadcast_caller_id_name = '$broadcast_caller_id_name', ";
    -			$sql .= "broadcast_caller_id_number = '$broadcast_caller_id_number', ";
    -			$sql .= "broadcast_destination_type = '$broadcast_destination_type', ";
    -
    -			//Update File selection and download sample 
    -			$sql .= "broadcast_phone_numbers = "; 
    -			$file_res = upload_file($sql,$broadcast_phone_numbers);
    -			if ($file_res['code'] == true) {
    -				$sql .= $file_res['sql'];
    +
    +		//prep update
    +			if ($action == "update" && permission_exists('call_broadcast_edit')) {
    +				//begin update array
    +					$array['call_broadcasts'][0]['call_broadcast_uuid'] = $call_broadcast_uuid;
    +
    +				//set message
    +					message::add($text['confirm-update']);
    +
    +				//set return url on error
    +					$error_return_url = "call_broadcast_edit.php?id=".$_GET['id'];
     			}
    -			else {
    -				$_SESSION["message_mood"] = "negative";
    -				$_SESSION["message"] = $text['file-error'];
    -				header("Location: call_broadcast_edit.php?id=".$_GET['id']);
    -				return false;
    +
    +		//execute
    +			if (is_array($array) && @sizeof($array) != 0) {
    +
    +				//add file selection and download sample
    +					$file_res = upload_file($sql, $broadcast_phone_numbers);
    +					if ($file_res['code'] != true) {
    +						$_SESSION["message_mood"] = "negative";
    +						$_SESSION["message"] = $text['file-error'];
    +						header("Location: ".$error_return_url);
    +						exit;
    +					}
    +					$broadcast_phone_numbers = $file_res['sql'];
    +
    +				//common array items
    +					$array['call_broadcasts'][0]['domain_uuid'] = $domain_uuid;
    +					$array['call_broadcasts'][0]['broadcast_name'] = $broadcast_name;
    +					$array['call_broadcasts'][0]['broadcast_description'] = $broadcast_description;
    +					$array['call_broadcasts'][0]['broadcast_timeout'] = strlen($broadcast_timeout) != 0 ? $broadcast_timeout : null;
    +					$array['call_broadcasts'][0]['broadcast_concurrent_limit'] = strlen($broadcast_concurrent_limit) != 0 ? $broadcast_concurrent_limit : null;
    +					//$array['call_broadcasts'][0]['recording_uuid'] = $recording_uuid;
    +					$array['call_broadcasts'][0]['broadcast_caller_id_name'] = $broadcast_caller_id_name;
    +					$array['call_broadcasts'][0]['broadcast_caller_id_number'] = $broadcast_caller_id_number;
    +					$array['call_broadcasts'][0]['broadcast_destination_type'] = $broadcast_destination_type;
    +					$array['call_broadcasts'][0]['broadcast_phone_numbers'] = $broadcast_phone_numbers;
    +					$array['call_broadcasts'][0]['broadcast_avmd'] = $broadcast_avmd;
    +					$array['call_broadcasts'][0]['broadcast_destination_data'] = $broadcast_destination_data;
    +					$array['call_broadcasts'][0]['broadcast_accountcode'] = $broadcast_accountcode;
    +
    +				//execute
    +					$database = new database;
    +					$database->app_name = 'call_broadcast';
    +					$database->app_uuid = 'efc11f6b-ed73-9955-4d4d-3a1bed75a056';
    +					$database->save($array);
    +					unset($array);
    +
    +				//redirect
    +					header("Location: call_broadcast.php");
    +					exit;
    +
     			}
    -			
    -			$sql .= "broadcast_avmd = '$broadcast_avmd', ";
    -			$sql .= "broadcast_destination_data = '$broadcast_destination_data', ";
    -			$sql .= "broadcast_accountcode = '$broadcast_accountcode' ";
    -			$sql .= "where domain_uuid = '$domain_uuid' ";
    -			$sql .= "and call_broadcast_uuid = '$call_broadcast_uuid'";
    -			echo $sql."<br><br>";
    -			$db->exec(check_sql($sql));
    -			unset($sql);
    -
    -			message::add($text['confirm-update']);
    -			header("Location: call_broadcast.php");
    -			return;
    -		} //if ($action == "update")
    -	} //if ($_POST["persistformvar"] != "true")
    -} //(count($_POST)>0 && strlen($_POST["persistformvar"]) == 0)
    +
    +	}
    +}
     
     //pre-populate the form
     	if (count($_GET)>0 && $_POST["persistformvar"] != "true") {
     		$call_broadcast_uuid = $_GET["id"];
     		$sql = "select * from v_call_broadcasts ";
    -		$sql .= "where domain_uuid = '$domain_uuid' ";
    -		$sql .= "and call_broadcast_uuid = '$call_broadcast_uuid' ";
    -		$prep_statement = $db->prepare(check_sql($sql));
    -		$prep_statement->execute();
    -		while($row = $prep_statement->fetch()) {
    +		$sql .= "where domain_uuid = :domain_uuid ";
    +		$sql .= "and call_broadcast_uuid = :call_broadcast_uuid ";
    +		$parameters['domain_uuid'] = $domain_uuid;
    +		$parameters['call_broadcast_uuid'] = $call_broadcast_uuid;
    +		$database = new database;
    +		$row = $database->select($sql, $parameters, 'row');
    +		if (is_array($row) && @sizeof($row) != 0) {
     			$broadcast_name = $row["broadcast_name"];
     			$broadcast_description = $row["broadcast_description"];
     			$broadcast_timeout = $row["broadcast_timeout"];
    @@ -298,9 +253,8 @@ function upload_file($sql,$broadcast_phone_numbers) {
     			$broadcast_avmd = $row["broadcast_avmd"];
     			$broadcast_destination_data = $row["broadcast_destination_data"];
     			$broadcast_accountcode = $row["broadcast_accountcode"];
    -			break; //limit to 1 row
     		}
    -		unset ($prep_statement);
    +		unset($sql, $parameters, $row);
     	}
     
     //begin header
    @@ -346,30 +300,33 @@ function upload_file($sql,$broadcast_phone_numbers) {
     		echo $text['description-accountcode']."\n";
     		echo "</td>\n";
     		echo "</tr>\n";
    -	}elseif (if_group("admin") &&  file_exists($_SERVER["PROJECT_ROOT"]."/app/billing/app_config.php")){
    -		$sql_accountcode = "SELECT type_value FROM v_billings WHERE domain_uuid = '".$_SESSION['domain_uuid']."'";
    -
    +	}
    +	else if (if_group("admin") &&  file_exists($_SERVER["PROJECT_ROOT"]."/app/billing/app_config.php")){
     		echo "<tr>\n";
     		echo "<td class='vncell' valign='top' align='left' nowrap='nowrap'>\n";
     		echo "    ".$text['label-accountcode']."\n";
     		echo "</td>\n";
     		echo "<td class='vtable' align='left'>\n";
     		echo "  <select name='broadcast_accountcode' id='broadcast_accountcode' class='formfld'>\n";
    -		$prep_statement_accountcode = $db->prepare(check_sql($sql_accountcode));
    -		$prep_statement_accountcode->execute();
    -		$result_accountcode = $prep_statement_accountcode->fetchAll(PDO::FETCH_NAMED);
    -		foreach ($result_accountcode as &$row_accountcode) {
    -			$selected = '';
    -			if (($action == "add") && ($row_accountcode['type_value'] == $_SESSION['domain_name'])){
    -				$selected='selected="selected"';
    +		$sql = "select type_value ";
    +		$sql .= "from v_billings ";
    +		$sql .= "where domain_uuid = :domain_uuid ";
    +		$parameters['domain_uuid'] = $_SESSION['domain_uuid'];
    +		$database = new database;
    +		$result = $database->select($sql, $parameters, 'all');
    +		if (is_array($result) && @sizeof($result) != 0) {
    +			foreach ($result as &$row) {
    +				$selected = '';
    +				if (($action == "add") && ($row['type_value'] == $_SESSION['domain_name'])){
    +					$selected='selected="selected"';
    +				}
    +				elseif ($row['type_value'] == $accountcode){
    +					$selected='selected="selected"';
    +				}
    +				echo "    <option value=\"".$row['type_value']."\" $selected>".$row['type_value']."</option>\n";
     			}
    -			elseif ($row_accountcode['type_value'] == $accountcode){
    -				$selected='selected="selected"';
    -			}
    -			echo "    <option value=\"".$row_accountcode['type_value']."\" $selected>".$row_accountcode['type_value']."</option>\n";
     		}
    -
    -		unset($sql_accountcode, $prep_statement_accountcode, $result_accountcode);
    +		unset($sql, $parameters, $result, $row);
     		echo "</select>";
     		echo "<br />\n";
     		echo $text['description-accountcode']."\n";
    
  • app/call_broadcast/call_broadcast.php+4 4 modified
    @@ -97,7 +97,7 @@
     	echo "</td>\n";
     	echo "</tr>\n";
     
    -	if (is_array($result)) {
    +	if (is_array($result) && @sizeof($result) != 0) {
     		foreach($result as $row) {
     			$tr_link = (permission_exists('call_broadcast_edit')) ? "href='call_broadcast_edit.php?id=".$row['call_broadcast_uuid']."'" : null;
     			echo "<tr ".$tr_link.">\n";
    @@ -122,9 +122,9 @@
     			echo "	</td>\n";
     			echo "</tr>\n";
     			if ($c==0) { $c=1; } else { $c=0; }
    -		} //end foreach
    -		unset($sql, $result, $row_count);
    -	} //end if results
    +		}
    +	}
    +	unset($sql, $result);
     
     	echo "<tr>\n";
     	echo "<td colspan='5' align='left'>\n";
    
  • app/call_broadcast/call_broadcast_stop.php+19 14 modified
    @@ -39,21 +39,26 @@
     	$text = $language->get();
     
     //get the html values and set them as variables
    -	if (count($_GET)>0) {
    -		$uuid = trim($_GET["id"]);
    -	}
    +	$uuid = trim($_GET["id"]);
    +
    +	if (is_uuid($uuid)) {
    +		//show the result
    +			if (count($_GET) > 0) {
    +				$fp = event_socket_create($_SESSION['event_socket_ip_address'], $_SESSION['event_socket_port'], $_SESSION['event_socket_password']);
    +				if ($fp) {
    +					$cmd = "sched_del ".$uuid;
    +					$result = event_socket_request($fp, 'api '.$cmd);
    +					message::add(htmlentities($result));
    +				}
    +			}
     
    -//show the header
    -	header('Location: call_broadcast_edit.php?id='.$uuid);
    -
    -//show the result
    -	if (count($_GET) > 0) {
    -		$fp = event_socket_create($_SESSION['event_socket_ip_address'], $_SESSION['event_socket_port'], $_SESSION['event_socket_password']);
    -		if ($fp) {
    -			$cmd = "sched_del ".$uuid;
    -			$result = event_socket_request($fp, 'api '.$cmd);
    -			message::add(htmlentities($result));
    -		}
    +		//redirect
    +			header('Location: call_broadcast_edit.php?id='.$uuid);
    +			exit;
     	}
     
    +//default redirect
    +	header('Location: call_broadcasts.php');
    +	exit;
    +
     ?>
    \ No newline at end of file
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.