CVE-2026-54812

Motors – Car Dealership & Classified Listings Plugin <= 1.4.109 - Unauthenticated SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
1.4.110
Patched in
7d
Time to patch

Description

The Motors – Car Dealership & Classified Listings Plugin plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.4.109 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.4.109
PublishedJune 17, 2026
Last updatedJune 23, 2026

What Changed in the Fix

Changes introduced in v1.4.110

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

_filtered_users`: `$distance_order` is interpolated directly. Where does `$distance_order` come from? `UserController::get_dealers` calls: `$model->order_by_location( $lat )` If `order_by_location` returns a string containing `$lat` and `$lat` isn't escaped... But…

Show full research plan

_filtered_users: $distance_orderis interpolated directly. Where does$distance_ordercome from? UserController::get_dealerscalls: $model->order_by_location( $lat ) Iforder_by_locationreturns a string containing$latand$latisn't escaped... Butlatis checked withfloatval`.

- Let's look at the parameters in `stm_listings_template_actions` again.
  Wait, look at this:
  `$action = apply_filters( 'stm_listings_input', null, 'ajax_action' );`
  The `stm_listings_input` filter is likely the source.
  In many Stylemix plugins, `stm_listings_input` returns `$_GET[$key]` or `$_POST[$key]`.
  If the code uses `stm_listings_input(null, 'some_param')` and injects it...

- Look at `includes/actions.php` -> `listings-result`:
  ```php
  if ( stm_is_multilisting() && ! empty( $_GET['posttype'] ) && ... ) {
      set_query_var( 'listings_type', $_GET['posttype'] );
      HooksMultiListing::stm_listings_attributes_filter( array( 'slug' => $_GET['posttype'] ) );
  }
  ```
Research Findings
Static analysis — not yet PoC-verified

Summary

The Motors – Car Dealership & Classified Listings Plugin is vulnerable to unauthenticated SQL Injection via the 'stm_lat' and 'stm_lng' parameters. These values are used to calculate distances in dealer searches and are concatenated directly into SQL queries without proper sanitization or parameter binding, allowing attackers to extract sensitive data from the database.

Vulnerable Code

// includes/class/User/UserController.php

$lat    = apply_filters( 'stm_listings_input', null, 'stm_lat' );
$lng    = apply_filters( 'stm_listings_input', null, 'stm_lng' );
$radius = apply_filters( 'motors_vl_get_nuxy_mod', '', 'distance_search' );
$radius = ( ! empty( $radius ) ) ? $radius : 5000;

if ( empty( $left_join ) && ! empty( floatval( $lat ) ) && ! empty( floatval( $lng ) ) ) {
    $include_users = $model->get_filtered_users_by_location( $model->fields_by_location( $lat, $lng ), $model->join_by_location( $lat ), $model->having_by_location( $lat, $radius ), $model->order_by_location( $lat ) );
} 

---

// includes/class/User/Model/UserModel.php

public function fields_by_location( $lat, $lng ) {
    if ( empty( $lat ) ) {
        return '';
    }
    $formula = "6378.137 * ACOS(COS(RADIANS(stm_lat_prefix.meta_value)) 
        * COS(RADIANS($lat)) 
        * COS(RADIANS(stm_lng_prefix.meta_value) - RADIANS($lng)) + SIN(RADIANS(stm_lat_prefix.meta_value)) 
        * SIN(RADIANS($lat))) AS distance";

    return ", $formula";
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/motors-car-dealership-classified-listings/1.4.109/includes/class/User/Model/UserModel.php /home/deploy/wp-safety.org/data/plugin-versions/motors-car-dealership-classified-listings/1.4.110/includes/class/User/Model/UserModel.php
--- /home/deploy/wp-safety.org/data/plugin-versions/motors-car-dealership-classified-listings/1.4.109/includes/class/User/Model/UserModel.php	2024-05-23 12:09:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/motors-car-dealership-classified-listings/1.4.110/includes/class/User/Model/UserModel.php	2026-05-28 16:12:22.000000000 +0000
@@ -191,9 +191,13 @@
 	}
 
 	public function fields_by_location( $lat, $lng ) {
-		if ( empty( $lat ) ) {
+		if ( false === filter_var( $lat, FILTER_VALIDATE_FLOAT ) || false === filter_var( $lng, FILTER_VALIDATE_FLOAT ) ) {
 			return '';
 		}
+
+		$lat = (float) $lat;
+		$lng = (float) $lng;
+
 		$formula = "6378.137 * ACOS(COS(RADIANS(stm_lat_prefix.meta_value)) 
 			* COS(RADIANS($lat)) 
 			* COS(RADIANS(stm_lng_prefix.meta_value) - RADIANS($lng)) + SIN(RADIANS(stm_lat_prefix.meta_value)) 
@@ -203,7 +207,7 @@
 	}
 
 	public function join_by_location( $lat ) {
-		if ( empty( $lat ) ) {
+		if ( false === filter_var( $lat, FILTER_VALIDATE_FLOAT ) ) {
 			return '';
 		}
 		$join  = " JOIN $this->user_meta_table AS stm_lat_prefix ON (u.ID = stm_lat_prefix.user_id AND stm_lat_prefix.meta_key = 'stm_dealer_location_lat')";
@@ -213,15 +217,17 @@
 	}
 
 	public function having_by_location( $lat, $radius ) {
-		if ( empty( $lat ) ) {
+		if ( false === filter_var( $lat, FILTER_VALIDATE_FLOAT ) || false === filter_var( $radius, FILTER_VALIDATE_FLOAT ) ) {
 			return '';
 		}
 
+		$radius = (float) $radius;
+
 		return "HAVING distance <= $radius";
 	}
 
 	public function order_by_location( $lat ) {
-		if ( empty( $lat ) ) {
+		if ( false === filter_var( $lat, FILTER_VALIDATE_FLOAT ) ) {
 			return '';
 		}
 
--- /home/deploy/wp-safety.org/data/plugin-versions/motors-car-dealership-classified-listings/1.4.109/includes/class/User/UserController.php
+++ /home/deploy/wp-safety.org/data/plugin-versions/motors-car-dealership-classified-listings/1.4.110/includes/class/User/UserController.php
@@ -64,12 +64,12 @@
 				}
 			}
 
-			$lat    = apply_filters( 'stm_listings_input', null, 'stm_lat' );
-			$lng    = apply_filters( 'stm_listings_input', null, 'stm_lng' );
-			$radius = apply_filters( 'motors_vl_get_nuxy_mod', '', 'distance_search' );
-			$radius = ( ! empty( $radius ) ) ? $radius : 5000;
+			$lat    = filter_var( apply_filters( 'stm_listings_input', null, 'stm_lat' ), FILTER_VALIDATE_FLOAT );
+			$lng    = filter_var( apply_filters( 'stm_listings_input', null, 'stm_lng' ), FILTER_VALIDATE_FLOAT );
+			$radius = filter_var( apply_filters( 'motors_vl_get_nuxy_mod', '', 'distance_search' ), FILTER_VALIDATE_FLOAT );
+			$radius = ( false !== $radius && $radius > 0 ) ? $radius : 5000;
 
-			if ( empty( $left_join ) && ! empty( floatval( $lat ) ) && ! empty( floatval( $lng ) ) ) {
+			if ( empty( $left_join ) && false !== $lat && false !== $lng ) {

Exploit Outline

The exploit targets the dealer listing functionality. An unauthenticated attacker can provide malicious SQL within the 'stm_lat' or 'stm_lng' query parameters. Although the plugin performs a loose check using `floatval()`, it passes the original string values to `UserModel` methods. These methods interpolate the strings directly into a complex SQL formula involving geographic coordinates. By crafting a payload like '1) [INJECTED SQL]', an attacker can break out of the `RADIANS()` function call and execute arbitrary SQL commands to exfiltrate data via error-based or time-based injection techniques.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.