CVE-2025-12361

myCred – Points Management System For Gamification, Ranks, Badges, and Loyalty Program <= 2.9.7.1 - Missing Authorization to Sensitive Information Exposure

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.9.7.2
Patched in
1d
Time to patch

Description

The myCred – Points Management System For Gamification, Ranks, Badges, and Loyalty Program plugin for WordPress is vulnerable to Missing Authorization in versions up to, and including, 2.9.7.1. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with Subscriber-level access and above, to retrieve sensitive information including user IDs, display names, and email addresses of all users on the site via the get_bank_accounts AJAX action. Passwords are not exposed.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.9.7.1
PublishedDecember 18, 2025
Last updatedDecember 19, 2025
Affected pluginmycred

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-12361 (myCred) ## 1. Vulnerability Summary The **myCred** plugin (<= 2.9.7.1) contains a missing authorization vulnerability in its AJAX handling logic. The plugin registers an AJAX action `get_bank_accounts` which, due to a lack of capability checks (e.g., `…

Show full research plan

Exploitation Research Plan - CVE-2025-12361 (myCred)

1. Vulnerability Summary

The myCred plugin (<= 2.9.7.1) contains a missing authorization vulnerability in its AJAX handling logic. The plugin registers an AJAX action get_bank_accounts which, due to a lack of capability checks (e.g., current_user_can()), allows any authenticated user (including those with Subscriber-level permissions) to trigger the function. The handler retrieves and returns sensitive user information, including IDs, display names, and email addresses for all users registered on the site, leading to sensitive information exposure.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: get_bank_accounts (Registered via wp_ajax_get_bank_accounts)
  • HTTP Method: POST or GET (WordPress AJAX handles both, but POST is standard).
  • Payload Parameter: action=get_bank_accounts.
  • Authentication: Required (Subscriber-level or higher).
  • Preconditions: The "Bank" transfer/gateway feature or addon in myCred must be active or the code path must be reachable via the registered AJAX hook.

3. Code Flow

  1. Registration: The plugin registers the action in a file typically related to banking or gateways (e.g., addons/bank-transfer/includes/mycred-bank-transfer-gateway.php or similar).
    • Likely Code: add_action( 'wp_ajax_get_bank_accounts', '...' );
  2. Handler Execution: When a Subscriber sends a request with action=get_bank_accounts, WordPress executes the associated callback function.
  3. Data Fetching: Inside the handler (e.g., get_bank_accounts()), the code performs a user query:
    • get_users() or a global $wpdb query against the users table.
  4. Information Leak: The retrieved user objects (containing user_email, display_name, and ID) are encoded into JSON and returned to the requester without verifying if the requester has administrative privileges.

4. Nonce Acquisition Strategy

The get_bank_accounts action likely requires a nonce for validation via check_ajax_referer or wp_verify_nonce. Since this is an authenticated-only vulnerability (Subscriber+), we must obtain a nonce issued to a logged-in user.

Discovery Steps:

  1. Identify Nonce Key: Search the codebase for wp_localize_script to find the JavaScript object name and nonce key.
    • Search patterns: grep -r "wp_create_nonce" . and grep -r "get_bank_accounts" .
    • Likely Localization: myCred often uses mycred_transfers or mycred_bank as JS objects.
  2. Extract Nonce via Browser:
    • A Subscriber user can find the nonce in the source code of their dashboard or a page where myCred scripts are loaded.
    • JS Variable (Inferred): mycred_bank_transfer.nonce or mycred_admin.nonce.
  3. Procedure for Agent:
    1. Create a Subscriber user and log in.
    2. Navigate to the WordPress dashboard (/wp-admin/).
    3. Execute browser_eval("window.mycred_bank_transfer?.nonce || window.mycred?.nonce") to find the active nonce.

5. Exploitation Strategy

Step 1: Authentication

Authenticate as a Subscriber user using the http_request tool to obtain session cookies.

Step 2: Nonce Extraction

Navigate to the dashboard and extract the nonce using browser_eval. Let's assume the nonce action is mycred-bank-transfer (typical for this plugin).

Step 3: Malicious AJAX Request

Send the exploit request to the AJAX endpoint.

Request Details:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
    • Cookie: [Subscriber Session Cookies]
  • Body:
    action=get_bank_accounts&_ajax_nonce=[EXTRACTED_NONCE]
    

Step 4: Data Parsing

The response is expected to be a JSON array. Extract and log the user_email and display_name fields to demonstrate the leak.

6. Test Data Setup

  1. Users:
    • Create an Admin user (victim): admin_user@example.com.
    • Create an Editor user (victim): editor_user@example.com.
    • Create a Subscriber user (attacker): attacker@example.com.
  2. Plugin Configuration:
    • Ensure the "Bank Transfer" or "Banking" addon is enabled in myCred settings (wp-admin/admin.php?page=mycred-addons).
    • If a specific shortcode is needed to trigger script loading for the nonce, create a page:
      wp post create --post_type=page --post_status=publish --post_content='[mycred_bank_transfer]'

7. Expected Results

  • HTTP Status: 200 OK.
  • Response Body: A JSON-encoded list of users.
    • Example: [{"ID":"1","display_name":"admin","user_email":"admin@site.com"},{"ID":"2","display_name":"Editor","user_email":"editor@site.com"}, ...]
  • Verification: The presence of the Admin's email address in the response received by the Subscriber-level account confirms the vulnerability.

8. Verification Steps

  1. Check Output: Verify the JSON response contains emails of users other than the attacker.
  2. Verify Permissions: Log in as the Subscriber and attempt to access the same data via standard UI (it should be hidden). The AJAX success proves the "Missing Authorization" bypass.
  3. Post-Exploit CLI Check: Use wp user list --fields=ID,user_email,display_name and compare the CLI output with the AJAX response to ensure 1:1 data parity.

9. Alternative Approaches

  • Different Nonces: If mycred-bank-transfer nonce doesn't work, search for generic nonces localized by myCred such as mycred-nonce or mycred-admin-nonce.
  • Parameter Guessing: If get_bank_accounts requires additional parameters like search or limit, try adding search=@ or limit=999 to ensure all users are returned.
  • Action Mapping: If wp_ajax_get_bank_accounts is not found, check if it's handled via a central mycred_action dispatcher:
    action=mycred_action&sub_action=get_bank_accounts.
Research Findings
Static analysis — not yet PoC-verified

Summary

The myCred plugin for WordPress is vulnerable to sensitive information exposure due to a missing authorization check in its get_bank_accounts AJAX handler. This allows authenticated users with Subscriber-level access to retrieve IDs, display names, and email addresses for all registered users on the site.

Vulnerable Code

// File: addons/bank-transfer/includes/mycred-bank-transfer-gateway.php

public function get_bank_accounts() {
    // Nonce is verified, but there is no capability check
    check_ajax_referer( 'mycred-bank-transfer', 'token' );

    // Retrieves sensitive user information without verifying user permissions
    $users = get_users( array( 'fields' => array( 'ID', 'display_name', 'user_email' ) ) );

    wp_send_json_success( $users );
}

Security Fix

--- a/addons/bank-transfer/includes/mycred-bank-transfer-gateway.php
+++ b/addons/bank-transfer/includes/mycred-bank-transfer-gateway.php
@@ -120,6 +120,10 @@
 	public function get_bank_accounts() {
 		check_ajax_referer( 'mycred-bank-transfer', 'token' );
 
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_send_json_error( array( 'message' => __( 'Permission denied', 'mycred' ) ) );
+		}
+
 		$users = get_users( array( 'fields' => array( 'ID', 'display_name', 'user_email' ) ) );
 
 		wp_send_json_success( $users );

Exploit Outline

The exploit involves an authenticated Subscriber user leveraging the lack of capability checks in the AJAX handler. First, the attacker authenticates to the WordPress site. Next, they extract a valid nonce for the 'mycred-bank-transfer' action, which is typically localized in the WordPress dashboard's HTML source within the 'mycred_bank_transfer' or similar JavaScript objects. Finally, the attacker sends a POST request to /wp-admin/admin-ajax.php with the parameters 'action=get_bank_accounts' and the extracted nonce. The server responds with a JSON array containing the IDs, display names, and email addresses of all registered users.

Check if your site is affected.

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