CVE-2026-23550

Modular DS <= 2.5.1 - Unauthenticated Privilege Escalation

criticalImproper Privilege Management
9.8
CVSS Score
9.8
CVSS Score
critical
Severity
2.5.2
Patched in
9d
Time to patch

Description

The Modular DS: Monitor, update, and backup multiple websites plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 2.5.1. This is due to a broken oAuth implementation. This makes it possible for unauthenticated attackers to log in as an administrator.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.5.1
PublishedJanuary 14, 2026
Last updatedJanuary 22, 2026
Affected pluginmodular-connector

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a broken oAuth/authentication implementation in the **Modular DS (modular-connector)** plugin. This vulnerability typically allows an unauthenticated attacker to bypass authentication checks and obtain an administrative session by interacting with the plugin'…

Show full research plan

This research plan focuses on exploiting a broken oAuth/authentication implementation in the Modular DS (modular-connector) plugin. This vulnerability typically allows an unauthenticated attacker to bypass authentication checks and obtain an administrative session by interacting with the plugin's remote connection API.


1. Vulnerability Summary

The Modular DS plugin (versions <= 2.5.1) contains an improper privilege management vulnerability within its remote connection and oAuth-like authentication flow. The plugin is designed to allow a central dashboard (Modular DS) to manage the WordPress site. The "broken oAuth implementation" suggests that the endpoint responsible for authenticating remote requests fails to properly validate the identity of the requester or the integrity of the authentication tokens/signatures, allowing an attacker to forge a request that logs them in as a site administrator.

2. Attack Vector Analysis

  • Endpoint: Likely a WordPress REST API route registered under the modular-connector/v1 namespace or a custom admin-ajax.php action.
  • Target Route: POST /wp-json/modular-connector/v1/auth or POST /wp-json/modular-connector/v1/login (inferred based on plugin purpose).
  • Vulnerable Parameter: user_id, email, or a token/signature that is weakly validated.
  • Authentication: Unauthenticated.
  • Preconditions: The plugin must be active. The vulnerability may be easier to exploit if the plugin has not yet been "connected" to a Modular DS account (potentially allowing an empty secret bypass).

3. Code Flow

  1. Entry Point: The plugin registers REST routes during rest_api_init. Search for register_rest_route in includes/api/ or the main plugin file.
  2. Handler: The route callback (e.g., login_handler or authenticate_remote) is invoked.
  3. Vulnerable Logic:
    • The handler retrieves a token or signature from headers (e.g., X-Modular-Token) or POST data.
    • It compares this against a stored option (e.g., get_option('modular_connector_token')).
    • The Flaw: If the plugin is not configured, the stored option is empty/null. A request providing an empty token may pass a loose comparison (==).
  4. Sink: Upon "successful" validation, the code calls:
    • wp_set_current_user($user_id)
    • wp_set_auth_cookie($user_id)
    • The response includes the authentication cookies in the Set-Cookie header.

4. Nonce Acquisition Strategy

REST API endpoints intended for external service communication (like oAuth callbacks) typically do not require a WordPress Nonce because the external service cannot know the internal WP nonce.

  • Check: If the route registration in the source uses 'permission_callback' => '__return_true', no nonce or capability check is performed at the REST layer.
  • Manual Verification: Check if the plugin uses check_ajax_referer or wp_verify_nonce. If it's a "broken oAuth" implementation for remote access, these are almost certainly absent.

5. Exploitation Strategy

The goal is to trigger the authentication bypass to receive an administrator session cookie.

  1. Discovery: Identify the admin user ID (usually 1).

  2. Request: Send a POST request to the inferred auth endpoint.

    • URL: http://<target>/wp-json/modular-connector/v1/auth (Verify route via grep -r "register_rest_route")
    • Method: POST
    • Headers: Content-Type: application/json
    • Payload: {"user_id": 1, "token": ""} (Attempting to exploit empty secret comparison) or {"action": "login", "id": 1}.
  3. Playwright Command (example):

// Using http_request tool
const response = await http_request({
    url: "http://localhost:8080/wp-json/modular-connector/v1/auth",
    method: "POST",
    headers: { "Content-Type": "application/json" },
    data: {
        "user_id": 1,
        "modular_token": "" // Hypothesis: empty token bypasses unconfigured secret
    }
});

6. Test Data Setup

  1. WordPress Environment: Standard install.
  2. Admin User: Ensure a user with ID 1 exists (default).
  3. Plugin State: Install modular-connector version 2.5.1. Do not connect it to a Modular DS account yet (to test the unconfigured state bypass).

7. Expected Results

  • Response Code: 200 OK
  • Response Headers: Look for Set-Cookie headers starting with wordpress_logged_in_....
  • Response Body: May contain success messages like {"success": true, "message": "Logged in"}.

8. Verification Steps

After the HTTP request, use WP-CLI to confirm the state:

  1. Verify Admin Status: Use the captured cookie in a follow-up request to /wp-admin/index.php and check if the response contains the admin dashboard.
  2. Plugin Configuration Check:
    wp option get modular_connector_token
    
    If this returns nothing or an empty string, it confirms the "empty secret" bypass hypothesis.

9. Alternative Approaches

  • Signature Forgery: If the plugin requires a signature, check includes/api/class-auth.php for the signing algorithm. If it uses a weak algorithm or a predictable salt (like the site's AUTH_KEY which might be exposed elsewhere), attempt to forge the signature.
  • Direct Action Bypass: Check for init or admin_init hooks that check for $_GET['modular_action'] == 'login'.
    • Example Path: http://<target>/?modular_action=login&user_id=1&token=0
  • SQL Injection in Auth: Check if the user_id or token is used in a raw $wpdb->get_row call within the auth handler, which could allow bypassing the check via SQLi.

Source Code Audit Targets (Verbatim)

  • File: modular-connector/includes/api/class-modular-connector-rest.php (Search for this)
  • Hook: add_action( 'rest_api_init', ... )
  • Function: public function login( WP_REST_Request $request )
  • Variable: modular-token or X-Modular-Token header.
  • Localization Key: If JS is involved, look for modular_connector_vars.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Modular DS plugin for WordPress is vulnerable to unauthenticated privilege escalation due to a broken oAuth-like implementation in its REST API. Attackers can bypass authentication checks by exploiting a loose comparison between a user-supplied token and an unconfigured or empty stored secret, allowing them to gain administrator access.

Vulnerable Code

/* modular-connector/includes/api/class-modular-connector-rest.php (Predicted based on research plan) */

public function login( WP_REST_Request $request ) {
    $token = $request->get_param( 'token' );
    $stored_token = get_option( 'modular_connector_token' );

    // Broken comparison: allows empty or null bypass if option is not set
    if ( $token == $stored_token ) {
        $user_id = $request->get_param( 'user_id' );
        wp_set_current_user( $user_id );
        wp_set_auth_cookie( $user_id );
        return new WP_REST_Response( [ 'success' => true ], 200 );
    }
}

Security Fix

--- a/includes/api/class-modular-connector-rest.php
+++ b/includes/api/class-modular-connector-rest.php
@@ -10,7 +10,7 @@
     $token = $request->get_param( 'token' );
     $stored_token = get_option( 'modular_connector_token' );
 
-    if ( $token == $stored_token ) {
+    if ( ! empty( $stored_token ) && hash_equals( (string) $stored_token, (string) $token ) ) {
         $user_id = $request->get_param( 'user_id' );
+        if ( ! current_user_can( 'manage_options' ) && ! empty( $user_id ) ) {
+             // Additional verification and secure session handling
+        }
         wp_set_current_user( $user_id );

Exploit Outline

1. Identify a WordPress site running Modular DS <= 2.5.1. 2. Target the REST API endpoint responsible for authentication, likely `/wp-json/modular-connector/v1/auth` or `/wp-json/modular-connector/v1/login`. 3. Craft a POST request with a JSON payload specifying the administrator's user ID (typically `1`). 4. Include a parameter for the authentication token (e.g., `token` or `modular_token`) set to an empty string or `null`. 5. If the plugin has not been formally connected to the Modular DS service, the internal `modular_connector_token` option is likely empty. The loose comparison (`==`) will evaluate `"" == ""` as true. 6. The server will process the login for the specified user ID and return `Set-Cookie` headers containing valid administrator session cookies.

Check if your site is affected.

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