Motors – Car Dealer, Classifieds & Listing <= 1.4.107 - Authenticated (Subscriber+) Arbitrary File Deletion via 'stm_dealer_logo_path' Parameter
Description
The Motors – Car Dealership & Classified Listings Plugin plugin for WordPress is vulnerable to arbitrary file deletion in all versions up to, and including, 1.4.107. This is due to insufficient file path validation in the become-dealer logo upload flow. The plugin allows any authenticated user to set an arbitrary filesystem path via the profile update handler. This makes it possible for authenticated attackers, with subscriber level access and above, to delete arbitrary files on the server.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:HTechnical Details
<=1.4.107What Changed in the Fix
Changes introduced in v1.4.108
Source Code
WordPress.org SVNThis research plan outlines the steps required to demonstrate the arbitrary file deletion vulnerability in the **Motors – Car Dealership & Classified Listings** plugin (CVE-2026-3892). ### 1. Vulnerability Summary The Motors plugin fails to validate the `stm_dealer_logo_path` parameter when updatin…
Show full research plan
This research plan outlines the steps required to demonstrate the arbitrary file deletion vulnerability in the Motors – Car Dealership & Classified Listings plugin (CVE-2026-3892).
1. Vulnerability Summary
The Motors plugin fails to validate the stm_dealer_logo_path parameter when updating a user's profile meta. An authenticated attacker with Subscriber-level privileges can set this meta field to an arbitrary filesystem path (e.g., wp-config.php). When the attacker subsequently triggers a logo update or deletion via the "Become Dealer" flow, the plugin's logic attempts to "clean up" the previous logo by calling unlink() on the path stored in the stm_dealer_logo_path meta, resulting in the deletion of the target file.
2. Attack Vector Analysis
- Vulnerable Parameter:
stm_dealer_logo_path - Injection Point: User Profile Update (
wp-admin/profile.phpor a frontend equivalent). - Trigger Point: The "Become Dealer" submission handler (
templates/user/private/become-dealer.php). - Authentication Level: Subscriber or higher.
- Preconditions: The attacker must be able to update their own user meta and then access the dealer registration form.
3. Code Flow
- Injection Phase:
- The plugin registers fields in
includes/user-extra.phpusing hooks likeshow_user_profile. - While the snippet shows
stm_user_avatar_path, the vulnerability exists in the handling ofstm_dealer_logo_path. - When a user updates their profile, the plugin (via truncated logic) saves POST parameters starting with
stm_directly to user meta without path validation.
- The plugin registers fields in
- Trigger Phase:
- The attacker navigates to the "Become Dealer" page (handled by
templates/user/private/become-dealer.php). - The attacker submits the form with a new
stm-avatarfile upload. - SINK: Inside the file upload handler (referenced around line 141), the plugin retrieves the existing path from the
stm_dealer_logo_pathuser meta. - EXECUTION: The plugin calls
unlink($old_path)to remove the previous logo before saving the new one. Because$old_pathis controlled by the attacker, any file can be deleted.
- The attacker navigates to the "Become Dealer" page (handled by
4. Nonce Acquisition Strategy
This vulnerability involves two steps: updating profile meta and triggering the deletion.
Phase 1: Profile Update (Admin Context)
To update the profile meta via the standard WordPress admin panel:
- Action:
update-user_{ID} - Nonce Key:
_wpnonce - Acquisition:
- Navigate to
wp-admin/profile.php. - Use
browser_evalto extract the nonce from the form:document.querySelector('#your-profile input[name="_wpnonce"]').value.
- Navigate to
Phase 2: Dealer Registration (Frontend Context)
If the deletion is triggered via the frontend "Become Dealer" form:
- The template
become-dealer.phpdoes not appear to use a dedicated nonce for the file upload (it relies onis_user_logged_in()). - If a nonce is required, it is likely localized as part of the theme/plugin's frontend scripts.
5. Exploitation Strategy
Step 1: Preparation
- Create a Subscriber user.
- Create a "canary" file to delete:
/var/www/html/wp-content/uploads/canary.php.
Step 2: Path Injection
Inject the target file path into the user's meta.
- Request Type: POST
- URL:
/wp-admin/profile.php - Headers:
Content-Type: application/x-www-form-urlencoded - Payload:
(Note: Include other required fields like email and nicknames to satisfy WordPress profile update requirements)._wpnonce=[NONCE]&action=update&user_id=[ID]&stm_dealer_logo_path=/var/www/html/wp-content/uploads/canary.php&email=[USER_EMAIL]...
Step 3: Trigger Deletion
Submit the "Become Dealer" form with a dummy image to trigger the cleanup logic.
- Request Type: POST (Multipart Form Data)
- URL: The URL of the page using the
become-dealer.phptemplate (e.g.,/become-dealer/or/account/become-dealer/). - Payload:
stm_company_name:Test Dealerstm_licence:12345stm_location:Londonstm-avatar: (A valid small.pngor.jpgfile)- Other required fields as defined in
required_fields(line 74 ofbecome-dealer.php).
6. Test Data Setup
- Canary File:
echo "<?php // canary ?>" > /var/www/html/wp-content/uploads/canary.php - User: Create a subscriber user
attacker. - Page Setup: Ensure a page exists with the "Become Dealer" functionality. This might require setting the page template to
become-dealervia WP-CLI:
(Note: Verify the exact shortcode or template name in the plugin settings or files).wp post create --post_type=page --post_title="Become Dealer" --post_status=publish --post_content="[stm_become_dealer]"
7. Expected Results
- The profile update request (Step 2) succeeds, and the database now stores the path to
canary.phpin theattacker's user meta. - The "Become Dealer" request (Step 3) processes the file upload.
- The plugin identifies the "old" logo path from meta and unlinks it.
- The file
/var/www/html/wp-content/uploads/canary.phpis deleted from the filesystem.
8. Verification Steps
After the HTTP requests, use WP-CLI to verify the deletion:
# Check if the file still exists
ls /var/www/html/wp-content/uploads/canary.php
# Check the user meta to see the new path (optional)
wp user meta get [ID] stm_dealer_logo_path
9. Alternative Approaches
If stm_dealer_logo_path is not directly editable via profile.php, check for an AJAX handler that updates dealer settings:
- Action:
stm_ajax_update_userorstm_ajax_save_settings. - If the plugin uses a frontend dashboard, the meta might be updated via a POST to the profile dashboard page with the same parameter name.
- Target File: If successful with the canary, the same method can target
wp-config.php, leading to a site-wide Denial of Service or allowing for a fresh reinstall.
Summary
The Motors – Car Dealership & Classified Listings plugin for WordPress is vulnerable to authenticated arbitrary file deletion due to insufficient path validation in the 'Become Dealer' logo upload flow. An attacker with subscriber-level access can set a target filesystem path in their user metadata and then trigger a file deletion by performing a logo update, which executes an unvalidated unlink() call on the stored path.
Vulnerable Code
// includes/user-extra.php around line 145 // The plugin exposes raw path fields in the user profile which are saved to user meta. <input type="text" name="stm_user_avatar_path" id="stm_user_avatar_path" value="<?php echo esc_attr( get_the_author_meta( 'stm_user_avatar_path', $user->ID ) ); ?>" class="regular-text"/> --- // templates/user/private/become-dealer.php (logic starting around line 141) // When a new logo is uploaded via the Become Dealer form, the plugin cleans up the old logo. $file = $_FILES['stm-avatar']; if ( is_array( $file ) && ! empty( $file['name'] ) ) { // ... logic to handle upload ... // The plugin retrieves the 'old' path from user meta (e.g., stm_dealer_logo_path) // SINK: The plugin calls unlink($old_path) without verifying it is within an allowed directory. unlink($old_path); }
Security Fix
@@ -1305,6 +1305,33 @@ add_filter( 'motors_vl_dealer_logo_placeholder', 'motors_vl_dealer_logo_placeholder' ); } +if ( ! function_exists( 'stm_mvl_is_path_within_uploads' ) ) { + function stm_mvl_is_path_within_uploads( $path ) { + if ( ! is_string( $path ) || '' === trim( $path ) ) { + return true; + } + $path = trim( $path ); + $dir = wp_upload_dir(); + if ( ! empty( $dir['error'] ) ) { + return false; + } + $upload_basedir = $dir['basedir']; + $real_upload = realpath( $upload_basedir ); + $real_path = realpath( $path ); + if ( false === $real_upload || false === $real_path ) { + return false; + } + return 0 === strpos( $real_path . DIRECTORY_SEPARATOR, $real_upload . DIRECTORY_SEPARATOR ); + } +} + +if ( ! function_exists( 'stm_mvl_filter_path_within_uploads' ) ) { + function stm_mvl_filter_path_within_uploads( $default, $path ) { + return stm_mvl_is_path_within_uploads( $path ); + } + add_filter( 'stm_mvl_is_path_within_uploads', 'stm_mvl_filter_path_within_uploads', 10, 2 ); +} +
Exploit Outline
1. Login as an authenticated user (Subscriber or higher). 2. Inject the target file path into the user's metadata (e.g., 'stm_dealer_logo_path') by submitting a POST request to /wp-admin/profile.php with the 'stm_dealer_logo_path' parameter set to the absolute path of the file you wish to delete (e.g., /var/www/html/wp-config.php). 3. Navigate to the 'Become Dealer' registration page. 4. Submit the 'Become Dealer' form and include an image file upload for the dealer logo ('stm-avatar'). 5. The plugin's submission handler identifies that a 'previous' logo path exists in the user's meta and attempts to delete it using unlink(). Because the path is attacker-controlled, the target file is deleted from the server.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.