TOP Table Of Contents <= 1.3.31 - Missing Authorization
Description
The TOP Table Of Contents plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 1.3.31. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.3.31What Changed in the Fix
Changes introduced in v1.4.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-25314 (TOP Table Of Contents) ## 1. Vulnerability Summary The **TOP Table Of Contents** plugin (versions <= 1.3.31) contains a missing authorization vulnerability in its AJAX implementation. Specifically, the function `Boomdevs_Toc_custom_plugin_install` is re…
Show full research plan
Exploitation Research Plan: CVE-2026-25314 (TOP Table Of Contents)
1. Vulnerability Summary
The TOP Table Of Contents plugin (versions <= 1.3.31) contains a missing authorization vulnerability in its AJAX implementation. Specifically, the function Boomdevs_Toc_custom_plugin_install is registered for both authenticated (wp_ajax_) and unauthenticated (wp_ajax_nopriv_) users but fails to perform any capability checks (e.g., current_user_can( 'install_plugins' )).
While the function is hardcoded to install a specific plugin (ai-image-alt-text-generator-for-wp), the lack of authorization allows any user (Subscriber and potentially unauthenticated users if they can obtain a nonce) to trigger the installation and activation of a plugin on the site, which is a significant unauthorized action.
2. Attack Vector Analysis
- AJAX Action:
Boomdevs_Toc_custom_plugin_install - Endpoint:
/wp-admin/admin-ajax.php - Authentication: Required (Subscriber-level access is sufficient to obtain the nonce).
- Nonce Requirement: Yes. The function uses
check_ajax_referer('Boomdevs_Toc_custom_plugin_install_nonce', 'security'). - Vulnerable Sink: The function calls
$upgrader->install(...)andactivate_plugin(...)without checking user permissions.
3. Code Flow
- Registration: In
admin/class-boomdevs-toc-admin.php, the AJAX hooks are registered:add_action('wp_ajax_Boomdevs_Toc_custom_plugin_install', [$this, 'Boomdevs_Toc_custom_plugin_install']); add_action('wp_ajax_nopriv_Boomdevs_Toc_custom_plugin_install', [$this, 'Boomdevs_Toc_custom_plugin_install']); - Nonce Generation: In the same file,
enqueue_scripts()localizes the nonce for the admin area:wp_localize_script($this->plugin_name, 'Boomdevs_Toc_custom_plugin_install_obj', array( 'ajax_url' => admin_url('admin-ajax.php'), 'security' => wp_create_nonce('Boomdevs_Toc_custom_plugin_install_nonce') ) ); - Vulnerable Function: The
Boomdevs_Toc_custom_plugin_installfunction inadmin/class-boomdevs-toc-admin.phpexecutes:- Validates the nonce via
securityparameter. - Hardcodes
$plugin_slug = 'ai-image-alt-text-generator-for-wp'. - Uses
Plugin_Upgraderto download and install from WordPress.org. - Calls
activate_plugin().
- Validates the nonce via
4. Nonce Acquisition Strategy
The nonce Boomdevs_Toc_custom_plugin_install_nonce is localized in the admin dashboard. Since even a Subscriber user can access /wp-admin/profile.php, they can retrieve this nonce.
- Login: Authenticate as a Subscriber-level user.
- Navigate: Go to
/wp-admin/. - Extract: Use
browser_evalto extract the nonce from the global JavaScript object:window.Boomdevs_Toc_custom_plugin_install_obj?.security
5. Exploitation Strategy
- Identify Target: Ensure the target WordPress instance is running TOP Table Of Contents <= 1.3.31.
- Obtain Nonce:
- Perform a login as a Subscriber.
- Use
browser_navigateto/wp-admin/. - Use
browser_evalto capture thesecuritytoken fromBoomdevs_Toc_custom_plugin_install_obj.
- Trigger Installation: Send an HTTP POST request to the AJAX endpoint.
- URL:
http://[target]/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=Boomdevs_Toc_custom_plugin_install&security=[NONCE]
- URL:
- Capture Response: A successful response should be a JSON object:
{"success":true,"data":{"message":"Plugin installed and activated successfully."}}.
6. Test Data Setup
- Plugin: Install "TOP Table Of Contents" version 1.3.31.
- User: Create a user with the
subscriberrole (e.g., username:attacker, password:password123). - Environment Check: Ensure the plugin
ai-image-alt-text-generator-for-wpis NOT currently installed.
7. Expected Results
- The AJAX request returns a success message.
- The
ai-image-alt-text-generator-for-wpplugin is downloaded intowp-content/plugins/. - The
ai-image-alt-text-generator-for-wpplugin appears as "Active" in the WordPress site.
8. Verification Steps
- WP-CLI Plugin Check:
Confirmwp plugin list --status=activeai-image-alt-text-generator-for-wpis in the list. - WP-CLI File Check:
Confirm the directory exists.ls -d wp-content/plugins/ai-image-alt-text-generator-for-wp/
9. Alternative Approaches
If the Subscriber user cannot access /wp-admin/ due to a site-wide lockdown (though standard WP allows profile access):
- Shortcode Extraction: Check if the plugin enqueues the same script on the frontend when a TOC is present. Create a page with
[boomdevs-toc]and try to extractBoomdevs_Toc_custom_plugin_install_objfrom the frontend. - Unauthenticated Check: Since
wp_ajax_noprivis registered, if an unauthenticated user can find any page whereenqueue_scriptsis called (or if the nonce is leaked via another vulnerability), they could trigger the install without logging in. Check thepublic/class-boomdevs-toc-public.php(not fully provided, but inferred) to see if scripts are shared.
Summary
The TOP Table Of Contents plugin for WordPress is vulnerable to unauthorized access because its AJAX handlers for plugin installation and layout imports lack capability checks. This allows authenticated users with subscriber-level permissions to trigger the installation and activation of a specific third-party plugin or modify site layout configurations.
Vulnerable Code
// admin/class-boomdevs-toc-admin.php lines 54-55 add_action('wp_ajax_Boomdevs_Toc_custom_plugin_install', [$this, 'Boomdevs_Toc_custom_plugin_install']); add_action( 'wp_ajax_nopriv_Boomdevs_Toc_custom_plugin_install', [$this, 'Boomdevs_Toc_custom_plugin_install'] ); // admin/class-boomdevs-toc-admin.php lines 156-184 public function Boomdevs_Toc_custom_plugin_install() { check_ajax_referer('Boomdevs_Toc_custom_plugin_install_nonce', 'security'); $plugin_slug = 'ai-image-alt-text-generator-for-wp'; $plugin_file = 'ai-image-alt-text-generator-for-wp/boomdevs-ai-image-alt-text-generator.php'; // Include necessary WordPress files for plugin installation and activation require_once ABSPATH . 'wp-admin/includes/plugin.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; // Install the plugin $upgrader = new Plugin_Upgrader(); $installed = $upgrader->install("https://downloads.wordpress.org/plugin/{$plugin_slug}.latest-stable.zip"); if (is_wp_error($installed)) { wp_send_json_error(array('message' => $installed->get_error_message())); } // Activate the plugin $activated = activate_plugin($plugin_file); if (is_wp_error($activated)) { wp_send_json_error(array('message' => $activated->get_error_message())); } wp_send_json_success(array('message' => 'Plugin installed and activated successfully.')); } --- // includes/class-boomdevs-toc-ajax.php line 16 public function get_premade_layout() { check_ajax_referer( 'layout_content', 'nonce' ); $default_available_skins_data = [ // ... (truncated)
Security Fix
@@ -52,7 +52,6 @@ $this->plugin_name = $plugin_name; $this->version = $version; add_action('wp_ajax_Boomdevs_Toc_custom_plugin_install', [$this, 'Boomdevs_Toc_custom_plugin_install']); - add_action( 'wp_ajax_nopriv_Boomdevs_Toc_custom_plugin_install', [$this, 'Boomdevs_Toc_custom_plugin_install'] ); } @@ -158,6 +157,10 @@ public function Boomdevs_Toc_custom_plugin_install() { + if ( ! current_user_can( 'install_plugins' ) ) { + wp_send_json_error( array( 'message' => __( 'You do not have permission to install plugins.', 'boomdevs-toc' ) ), 403 ); + } + check_ajax_referer('Boomdevs_Toc_custom_plugin_install_nonce', 'security'); $plugin_slug = 'ai-image-alt-text-generator-for-wp'; @@ -15,6 +15,10 @@ */ public function get_premade_layout() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => __( 'You do not have permission to perform this action.', 'boomdevs-toc' ) ), 403 ); + } + check_ajax_referer( 'layout_content', 'nonce' ); $default_available_skins_data = [ @@ -254,7 +254,6 @@ private function register_ajax_hooks() { $plugin_ajax = new Boomdevs_Toc_Ajax(); - $this->loader->add_action('wp_ajax_nopriv_get_premade_layout', $plugin_ajax, 'get_premade_layout'); $this->loader->add_action('wp_ajax_get_premade_layout', $plugin_ajax, 'get_premade_layout'); }
Exploit Outline
To exploit this vulnerability, an attacker first authenticates as a Subscriber user and navigates to the WordPress dashboard (e.g., /wp-admin/profile.php). By inspecting the global JavaScript object 'Boomdevs_Toc_custom_plugin_install_obj' localized on the page, the attacker retrieves the 'security' nonce. The attacker then sends an HTTP POST request to the '/wp-admin/admin-ajax.php' endpoint with the 'action' parameter set to 'Boomdevs_Toc_custom_plugin_install' and the 'security' parameter set to the captured nonce. Because the server-side function lacks a capability check (e.g., current_user_can('install_plugins')), it will proceed to download and activate the hardcoded 'ai-image-alt-text-generator-for-wp' plugin from the WordPress repository.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.