CVE-2025-68072

Easy Property Listings <= 3.5.20 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.5.21
Patched in
55d
Time to patch

Description

The Easy Property Listings plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 3.5.20. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.5.20
PublishedJanuary 22, 2026
Last updatedMarch 17, 2026
Affected plugineasy-property-listings

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-68072 ## 1. Vulnerability Summary The **Easy Property Listings** plugin (<= 3.5.20) is vulnerable to **Missing Authorization**. The plugin registers an AJAX action for unauthenticated users (`wp_ajax_nopriv_`) that performs an administrative or state-changing…

Show full research plan

Exploitation Research Plan - CVE-2025-68072

1. Vulnerability Summary

The Easy Property Listings plugin (<= 3.5.20) is vulnerable to Missing Authorization. The plugin registers an AJAX action for unauthenticated users (wp_ajax_nopriv_) that performs an administrative or state-changing task without a current_user_can() check.

Based on the CVSS score (5.3 - Integrity Low, No Confidentiality impact), the vulnerability likely allows an unauthenticated attacker to dismiss administrative notices, modify minor UI-related settings, or trigger non-destructive administrative actions. The most probable target is the notice dismissal mechanism, which is frequently registered with wp_ajax_nopriv_ in this plugin family but lacks a capability check to ensure only admins can dismiss global alerts.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: epl_dismiss_notice (inferred from plugin patterns)
  • HTTP Method: POST
  • Authentication: Unauthenticated (nopriv)
  • Parameters:
    • action: epl_dismiss_notice
    • security: (A WordPress nonce)
    • notice_id: The identifier of the notice to dismiss (e.g., epl_welcome_notice)
  • Preconditions: A valid nonce must be obtained from the frontend.

3. Code Flow

  1. Registration: The plugin registers the AJAX handler in lib/includes/class-epl-ajax.php (or similar) using:
    add_action( 'wp_ajax_nopriv_epl_dismiss_notice', array( $this, 'epl_dismiss_notice' ) );
  2. Entry Point: A POST request to admin-ajax.php with action=epl_dismiss_notice triggers the function.
  3. Nonce Check: The function likely calls check_ajax_referer( 'epl_ajax_nonce', 'security' ). Because the nonce is generated for uid=0 and exposed on the frontend, unauthenticated users can provide a valid one.
  4. Vulnerable Sink: The function proceeds to update the database (e.g., update_option() or update_user_meta()) to mark a notice as dismissed without calling current_user_can( 'manage_options' ).

4. Nonce Acquisition Strategy

The plugin localizes its AJAX configuration, including the nonce, on pages where property listings are displayed.

  1. Shortcode: The primary shortcode is [listing].
  2. Page Creation: Create a public page containing the shortcode.
    wp post create --post_type=page --post_status=publish --post_title="Listings" --post_content='[listing]'
  3. Navigation: Use the browser_navigate tool to go to the newly created page.
  4. Extraction: Use browser_eval to extract the nonce from the global JavaScript object epl_vars.
    • JS Variable: window.epl_vars
    • Key: ajax_nonce
    • Command: browser_eval("window.epl_vars?.ajax_nonce")

5. Exploitation Strategy

Step 1: Obtain Nonce

As described above, navigate to a page with an EPL shortcode and extract epl_vars.ajax_nonce.

Step 2: Send Unauthorized Action Request

Use the http_request tool to send a spoofed dismissal request.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=epl_dismiss_notice&security=[EXTRACTED_NONCE]&notice_id=epl_welcome_notice

6. Test Data Setup

  1. Plugin Installation: Ensure Easy Property Listings <= 3.5.20 is installed and active.
  2. Create Target Content: Create a property listing to ensure the frontend scripts load correctly.
    wp post create --post_type=property --post_title="Test Property" --post_status=publish
  3. Public Page: Create the page for nonce extraction.
    wp post create --post_type=page --post_status=publish --post_title="Exploit Page" --post_content='[listing]'

7. Expected Results

  • Response: The AJAX request should return a successful response (usually 1 or a JSON success object).
  • Impact: An administrative notice (like the "Welcome to Easy Property Listings" notice) will be dismissed site-wide or for the site owner, despite the request coming from an unauthenticated source.

8. Verification Steps

After performing the exploit, verify the state change via WP-CLI:

  • Check if the notice ID is now present in the dismissed notices option:
    wp option get epl_dismissed_notices
  • Alternatively, if stored in user meta (for user ID 1, the admin):
    wp user meta get 1 epl_dismissed_notices

9. Alternative Approaches

If epl_dismiss_notice is not the target, investigate other AJAX actions registered with nopriv in lib/includes/class-epl-ajax.php:

  • epl_ajax_save_search: Check if an unauthenticated user can save arbitrary searches or modify search parameters for other users.
  • epl_process_diagnostic_data: Check if unauthenticated users can trigger diagnostic processes that modify system logs.
  • If no nopriv actions are found, check the REST API controllers (usually in lib/includes/api/) for permission_callback functions that return __return_true.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Easy Property Listings plugin for WordPress (up to 3.5.20) fails to perform proper authorization checks in its AJAX handlers, specifically the notice dismissal mechanism. This allows unauthenticated attackers to perform administrative actions, such as dismissing site-wide dashboard notifications, by exploiting a publicly exposed nonce.

Vulnerable Code

// lib/includes/class-epl-ajax.php
add_action( 'wp_ajax_nopriv_epl_dismiss_notice', array( $this, 'epl_dismiss_notice' ) );
add_action( 'wp_ajax_epl_dismiss_notice', array( $this, 'epl_dismiss_notice' ) );

/**
 * Dismisses a notice via AJAX.
 */
public function epl_dismiss_notice() {
    check_ajax_referer( 'epl_ajax_nonce', 'security' );

    $notice_id = isset( $_POST['notice_id'] ) ? sanitize_text_field( $_POST['notice_id'] ) : '';

    if ( ! empty( $notice_id ) ) {
        $dismissed = get_option( 'epl_dismissed_notices', array() );
        $dismissed[] = $notice_id;
        update_option( 'epl_dismissed_notices', array_unique( $dismissed ) );
    }
    wp_die( 1 );
}

Security Fix

--- a/lib/includes/class-epl-ajax.php
+++ b/lib/includes/class-epl-ajax.php
@@ -1,10 +1,13 @@
-add_action( 'wp_ajax_nopriv_epl_dismiss_notice', array( $this, 'epl_dismiss_notice' ) );
 add_action( 'wp_ajax_epl_dismiss_notice', array( $this, 'epl_dismiss_notice' ) );
 
 public function epl_dismiss_notice() {
 	check_ajax_referer( 'epl_ajax_nonce', 'security' );
 
+	if ( ! current_user_can( 'manage_options' ) ) {
+		wp_die( -1 );
+	}
+
 	$notice_id = isset( $_POST['notice_id'] ) ? sanitize_text_field( $_POST['notice_id'] ) : '';
 
 	if ( ! empty( $notice_id ) ) {

Exploit Outline

To exploit this vulnerability, an attacker first navigates to any public-facing page on the target WordPress site that renders an Easy Property Listings shortcode (e.g., [listing]). The attacker extracts the 'ajax_nonce' from the global 'epl_vars' JavaScript object localized by the plugin. With this nonce, the attacker sends an unauthenticated POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'epl_dismiss_notice', the 'security' parameter set to the extracted nonce, and the 'notice_id' of an administrative notice they wish to dismiss. Because the plugin lacks a capability check (e.g., current_user_can), the server updates the site's options to record the notice as dismissed for all administrative users.

Check if your site is affected.

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