Multiple vulnerabilities in WordPress Motors Car Dealer & Classified Ads plugin.

The WordPress Motors Car Dealer & Classified Ads plugin, which has 10,000+ active installations, was prone to multiple vulnerabilities in version 1.4.0 and below.


CVE-2019-17228, CVE-2019-17229

Unauthenticated settings import/export and stored XSS

In the “includes/options.php” script, the stm_export_settings function is registered via the init hook and thus is called whenever the blog is accessed:

function stm_export_settings()
    if (!empty($_GET['export_settings'])) {
        $options = get_option('stm_vehicle_listing_options');

        header('Content-disposition: attachment; filename=file.json');
        header('Content-type: application/json');
        echo json_encode($options);

    if (!empty($_FILES) && !empty($_FILES['import_settings']) && !empty($_FILES['import_settings']['tmp_name'])) {
        $json = json_decode(file_get_contents($_FILES['import_settings']['tmp_name']), true);
        if (!empty($json)) {
            update_option('stm_vehicle_listing_options', $json);


add_action('init', 'stm_export_settings');

The function is used to import and export the plugin options: it lacks capability check and a security nonce and therefore is accessible to anyone.

The imported options, which are displayed in the CMS back-end, are managed by the “includes/admin/categories.php” script. Its stm_vehicles_listings_show_field function is used to build the HTML form and to insert the imported values:

function stm_vehicles_listings_show_field($name, $settings, $values) {
   $type = 'stm_vehicle_listings_field_text';
   if(!empty($settings['type'])) {
      $type = 'stm_vehicle_listings_field_' . $settings['type'];

   $type($name, $settings, $values);

It calls six different stm_vehicle_listings_field_* functions to build the HTML form elements (e.g., text, select, radio input fields) such as this one, stm_vehicle_listings_field_text:

function stm_vehicle_listings_field_text($name, $settings, $values) {
   $value = (!empty($values[$name])) ? $values[$name] : '';
   $atts = (!empty($settings['attributes'])) ? $settings['attributes'] : array();
   $input_atts = '';
   if(!empty($atts)) {
      foreach($atts as $key => $att) {
         $input_atts .= $key . '="' . $att . '" ';
   <div class="stm_form_wrapper stm_form_wrapper_<?php echo $settings['type']; ?> stm_form_wrapper_<?php echo $name; ?> <?php stm_vehicles_listing_has_preview($settings); ?>" <?php stm_vehicles_listing_show_dependency($settings); ?>>
         <span><?php echo $settings['label']; ?></span>
         <input <?php echo $input_atts; ?> type="<?php echo $settings['type'] ?>" name="<?php echo $name; ?>" value="<?php echo $value; ?>" />
      <?php stm_vehicles_listings_preview($settings); ?>
<?php }

None of the six functions validate or sanitize the imported values.

An unauthenticated user can export the plugin configuration, inject JavaScript or any other HTML code into one of the several vulnerable fields, and re-import the plugin options, which could lead to multiple stored XSS vulnerabilities in the back-end section of WordPress when the admin visits the plugin configuration page:

Additional issues

Several additional security issues were found in Motors Car Dealer & Classified Ads.

1. Authenticated settings import

The plugin allows the administrator to import an XML file from WebManager. All functions handling the imported data are located in the following two scripts:

  • includes/automanager/xml-importer-automanager-ajax.php: The stm_ajax_file_automanager_upload, stm_ajax_automanager_save_associations and stm_ajax_automanager_save_template functions are accessible to any authenticated users via the WordPress AJAX API.
  • includes/automanager/xml-importer-automanager-iframe.php: The stmImportXML function, which loads via the admin_init hook, is accessible to any unauthenticated users.

2. Unsanitized inputs

The “templates/single-car/car-price.php” script is one of the templates used to display the users ads on the blog front-end. Lines 57, 71, 95, 104 and 121, the author misused the PHP prinft and WordPress esc_html__ functions. For instance:

<?php printf(esc_html__('%s', 'stm_vehicles_listing'), $regular_price_label); ?>

The problem with the above code is that only %s will be sanitized, not the content of the $regular_price_label variable.

3. Authenticated options change

All four AJAX functions found in the “includes/options.php” script (stm_listings_save_single_option_row, stm_listings_delete_single_option_row, stm_listings_save_option_order, stm_listings_add_new_option) lack security nonces and capability check, allowing an authenticated user to modify, add or delete options and inject JS code similarly to the main unauthenticated settings import vulnerability described earlier.


A new version 1.4.1 was released on September 18, 2019.


Update as soon as possible if you have version 1.4.0 or below installed.
If you are using our web application firewall for WordPress, NinjaFirewall WP Edition (free) and NinjaFirewall WP+ Edition (premium), you are protected against this vulnerability.

Stay informed about the latest vulnerabilities in WordPress plugins and themes: @nintechnet