CVE-2025-6792

One to one user Chat by WPGuppy <= 1.1.4 - Unauthenticated Information Disclosure via Chat Message Interception

mediumMissing Authentication for Critical Function
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The One to one user Chat by WPGuppy plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the /wp-json/guppylite/v2/channel-authorize rest endpoint in all versions up to, and including, 1.1.4. This makes it possible for unauthenticated attackers to intercept and view private chat messages between users.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.1.4
PublishedFebruary 13, 2026
Last updatedApril 15, 2026
Affected pluginwpguppy-lite
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-6792 ## 1. Vulnerability Summary The **One to one user Chat by WPGuppy** plugin (lite version) up to 1.1.4 is vulnerable to **Unauthenticated Information Disclosure**. The vulnerability exists in the registration of the `/wp-json/guppylite/v2/channel-authoriz…

Show full research plan

Exploitation Research Plan - CVE-2025-6792

1. Vulnerability Summary

The One to one user Chat by WPGuppy plugin (lite version) up to 1.1.4 is vulnerable to Unauthenticated Information Disclosure. The vulnerability exists in the registration of the /wp-json/guppylite/v2/channel-authorize REST API endpoint. The plugin fails to implement a proper permission_callback (or implements one that always returns true), allowing unauthenticated users to obtain authorization signatures for private chat channels. These signatures are typically used to subscribe to real-time message streams (like Pusher), enabling an attacker to intercept and view private communications between any two users.

2. Attack Vector Analysis

  • Endpoint: /wp-json/guppylite/v2/channel-authorize
  • Method: POST (typically for authorization endpoints in this plugin)
  • Vulnerable Parameter: channel_name
  • Authentication: None required (Unauthenticated).
  • Preconditions:
    1. The plugin must be active.
    2. The attacker needs to know or guess the IDs of the two users whose chat they wish to intercept.
    3. A chat channel must follow a predictable naming convention (e.g., private-guppy-chat-{ID1}-{ID2}).

3. Code Flow (Inferred)

  1. Route Registration: The plugin registers REST routes during the rest_api_init hook.
  2. Missing Check: In the register_rest_route call for guppylite/v2/channel-authorize, the permission_callback is either missing, set to __return_true, or lacks a current_user_can() check that validates if the requesting user is actually one of the participants in the channel_name.
  3. Authorization Logic:
    • The handler receives a channel_name (e.g., private-guppy-chat-1-2) and a socket_id.
    • It uses the plugin's internal secret key/Pusher credentials to generate an HMAC signature for that socket_id and channel_name.
    • It returns this signature to the unauthenticated requester.
  4. Information Disclosure: With this signature, the attacker can connect to the chat websocket and receive all messages sent between User 1 and User 2.

4. Nonce Acquisition Strategy

While REST API endpoints with permission_callback => '__return_true' often don't strictly require a nonce for GET requests, POST requests in WordPress usually require the X-WP-Nonce header to pass the internal CSRF check if any cookies are present. For a purely unauthenticated attack, we should attempt the request without a nonce first. If it fails, we will extract the REST nonce.

  1. Identify Script Loading: The WPGuppy Lite plugin typically enqueues its assets on pages where the chat UI is present or via a general initialization.
  2. Create Trigger Page:
    wp post create --post_type=page --post_status=publish --post_title="Chat Test" --post_content='[wpguppy_lite_chat]' (Shortcode inferred from common WPGuppy patterns).
  3. Navigate and Extract:
    Navigate to the newly created page and look for the localized JS object, usually named guppylite_vars or wpguppy_lite_vars.
  4. Browser Eval:
    browser_eval("window.guppylite_vars?.nonce") or browser_eval("window.guppylite_vars?.rest_nonce").

5. Exploitation Strategy

Step 1: Discover Target User IDs

The attacker can identify target user IDs via the standard WordPress REST API:
GET /wp-json/wp/v2/users

Step 2: Request Channel Authorization

Assuming we want to intercept messages between User 1 (Admin) and User 2 (Customer). The predictable channel name is private-guppy-chat-1-2.

HTTP Request:

POST /wp-json/guppylite/v2/channel-authorize HTTP/1.1
Host: target.local
Content-Type: application/x-www-form-urlencoded
X-WP-Nonce: [OPTIONAL_NONCE]

channel_name=private-guppy-chat-1-2&socket_id=12345.67890

Step 3: Analyze Response

A successful exploit will return a JSON object containing the authentication string required to join the private channel.

Expected Success Response:

{
    "auth": "pusher_key:xxxxxxxxxxxxxxxxxxxx",
    "channel_data": "..." 
}

Note: If the plugin returns the auth string to an unauthenticated user for a channel they don't belong to, the vulnerability is confirmed.

6. Test Data Setup

  1. Users: Ensure at least two users exist.
    • User 1: wp user create victim1 victim1@example.com --role=administrator
    • User 2: wp user create victim2 victim2@example.com --role=subscriber
  2. Plugin Config: Install and activate wpguppy-lite version 1.1.4.
  3. Interaction: (Optional but helpful) Simulate a chat initialization between the two users so the channel is recognized by the system.

7. Expected Results

  • The REST endpoint returns a 200 OK status code.
  • The response body contains an auth token or signature for a private channel.
  • The request succeeds even when no authentication cookies or headers are provided.

8. Verification Steps

  1. Check REST Response: Verify the JSON response contains the auth key.
  2. Verify Authentication Level: Confirm the request was made without a Cookie header or Authorization header.
  3. Manual Code Audit: Use WP-CLI to inspect the route registration:
    wp eval "print_r( $GLOBALS['wp_rest_server']->get_routes()['guppylite/v2'] );"
    Check if the channel-authorize entry has a permission_callback and if that callback performs an is_user_logged_in() or current_user_can() check.

9. Alternative Approaches

  • Different Channel Patterns: If private-guppy-chat-1-2 fails, try variations like guppy-chat-1-2, private-chat-1-2, or check the JS source on the frontend to find the exact string format used in wpguppy-lite.js.
  • GET vs POST: If POST is blocked, attempt a GET request with the same parameters.
  • Information Leakage in Params: Check if other endpoints in guppylite/v2 (like get-messages) are also missing permission checks, which would allow direct history disclosure instead of just real-time interception.
Research Findings
Static analysis — not yet PoC-verified

Summary

The One to one user Chat by WPGuppy plugin for WordPress is vulnerable to unauthenticated information disclosure due to a missing permission check on its REST API authorization endpoint. Attackers can obtain valid authentication signatures for private chat channels, allowing them to intercept and monitor real-time private messages between any two users by guessing their user IDs.

Vulnerable Code

// From the REST route registration logic (likely in an initialization class)
register_rest_route('guppylite/v2', '/channel-authorize', array(
    'methods'             => 'POST',
    'callback'            => array($this, 'channel_authorize'),
    'permission_callback' => '__return_true', // Vulnerability: Allows unauthenticated access
));

---

// The callback function typically generates an HMAC for Pusher/Websocket usage
public function channel_authorize($request) {
    $channel_name = $request->get_param('channel_name');
    $socket_id = $request->get_param('socket_id');
    
    // Logic to generate Pusher auth signature without verifying if the 
    // current user belongs to the requested channel_name
    $auth = $this->pusher->socket_auth($channel_name, $socket_id);
    return new WP_REST_Response($auth, 200);
}

Security Fix

--- a/includes/class-wp-guppy-lite-rest.php
+++ b/includes/class-wp-guppy-lite-rest.php
@@ -10,7 +10,13 @@
         register_rest_route('guppylite/v2', '/channel-authorize', array(
             'methods'             => 'POST',
             'callback'            => array($this, 'channel_authorize'),
-            'permission_callback' => '__return_true',
+            'permission_callback' => function ($request) {
+                if (!is_user_logged_in()) {
+                    return false;
+                }
+                // Additional logic should verify if the user is a participant 
+                // in the requested channel_name
+                return true;
+            },
         ));

Exploit Outline

1. Identify target user IDs by querying the public WordPress users endpoint: /wp-json/wp/v2/users. 2. Determine the target channel name convention, which typically follows a predictable pattern like 'private-guppy-chat-{user_id_1}-{user_id_2}'. 3. Send an unauthenticated POST request to /wp-json/guppylite/v2/channel-authorize containing the guessed channel_name and a dummy socket_id. 4. Capture the JSON response containing the 'auth' signature generated by the plugin's internal secret key. 5. Use the provided authentication signature and the third-party service (e.g., Pusher) to subscribe to the private chat channel. 6. Listen to the stream to intercept and view private messages sent between the two victim users in real-time.

Check if your site is affected.

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