Modular Connector <= 2.5.1 - Cross-Site Request Forgery via postConfirmOauth
Description
The Modular DS: Monitor, update, and backup multiple websites plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 2.5.1. This is due to missing nonce validation on the postConfirmOauth() function. This makes it possible for unauthenticated attackers to disconnect the plugin's OAuth/SSO connection via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<=2.5.1What Changed in the Fix
Changes introduced in v2.6.0
Source Code
WordPress.org SVNThis research plan targets a CSRF vulnerability in the Modular Connector plugin, which allows an attacker to disconnect the site from the Modular DS dashboard by tricking an administrator into submitting a forged request to the `postConfirmOauth()` handler. ## 1. Vulnerability Summary * **Vulnera…
Show full research plan
This research plan targets a CSRF vulnerability in the Modular Connector plugin, which allows an attacker to disconnect the site from the Modular DS dashboard by tricking an administrator into submitting a forged request to the postConfirmOauth() handler.
1. Vulnerability Summary
- Vulnerability: Cross-Site Request Forgery (CSRF)
- Component:
OauthController::postConfirmOauth()(Inferred location based on standard plugin architecture and provided controllers). - Affected Versions: <= 2.5.1
- Impact: An attacker can force the WordPress site to disconnect from its management dashboard (Modular DS). This disrupts backups, monitoring, and security scans.
- Root Cause: The
postConfirmOauthfunction, which handles the finalization of the OAuth connection flow, fails to implement WordPress nonce validation (check_admin_refererorcheck_ajax_referer).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.phpor/wp-admin/admin-post.php(The plugin uses a custom dispatcher). - Action:
modular_connector_oauth_confirmormodular_connector_confirm_oauth(Inferred). - Method:
POST - Authentication: Requires an active administrator session (Victim).
- Parameters:
action: The hook registered to reach the dispatcher.route:/oauth/confirm(Inferred based on the Laravel-style routing seen inBackupController.php).
3. Code Flow
- Entry Point: An administrator visits a malicious page while logged into the WordPress site.
- Request Trigger: The malicious page auto-submits a POST request to
wp-admin/admin-ajax.php. - Hook Registration:
init.phpcalls\Modular\Connector\WordPress\Admin::setup(), which registers AJAX or admin-post actions. - Routing: The action maps to a dispatcher that instantiates
Modular\Connector\Http\Controllers\OauthController. - Vulnerable Sink: The dispatcher calls
postConfirmOauth(). Because this function lacks a nonce check, it proceeds to process the "confirmation" request. - Action Taken: The function likely attempts to refresh or update the OAuth credentials. If provided with malformed or empty data via CSRF, it fails the handshake and clears the existing valid credentials in
_modular_connection_access_tokenand_modular_connection_client_id(seen inModularClient.php), effectively disconnecting the site.
4. Nonce Acquisition Strategy
According to the vulnerability description, this function is vulnerable specifically because it misses nonce validation. Therefore, no nonce is required to exploit this vulnerability.
5. Exploitation Strategy
Step 1: Discover exact action and route
Since the full controller and route files are not provided, the agent must first find the exact action string.
- Search for the method definition:
grep -r "function postConfirmOauth" . - Search for where this controller/method is routed:
grep -r "oauth" .and look for strings likeadd_actionorRoute::post.
Step 2: Simulate Connected State
Before testing, ensure the plugin is "connected" so we can verify the disconnection.
- Set fake connection options:
wp option update _modular_connection_client_id "fake_client_id" wp option update _modular_connection_access_token "fake_access_token"
Step 3: Execute CSRF
The agent will simulate the Admin's browser making the forged request using the http_request tool.
Hypothesized Request (to be refined by discovery):
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Body (URL Encoded):
(Note: If discovery shows a different action name likeaction=modular_connector_request&route=/oauth/confirmmodular_connector_oauth_confirm, use that instead).
Step 4: Verification
Confirm that the options have been cleared or modified, indicating a disconnection.
6. Test Data Setup
- Plugin Installation: Ensure
modular-connectorversion 2.5.1 is active. - Admin User: Ensure a standard admin user exists (e.g.,
admin/password). - Connection Simulation:
wp option update _modular_connection_client_id "poc_test_client" wp option update _modular_connection_access_token "poc_test_token"
7. Expected Results
- The
POSTrequest should return a200 OKor302 Redirect. - The WordPress options associated with the Modular DS connection should be deleted or set to empty strings.
- The response from the server should NOT be a "403 Forbidden" or a "Nonce Verification Failed" error.
8. Verification Steps
- Check the connection options via WP-CLI:
wp option get _modular_connection_client_id wp option get _modular_connection_access_token - Success Condition: The commands return an empty value or an error stating the option does not exist, whereas they previously contained "poc_test_client" and "poc_test_token".
9. Alternative Approaches
If the admin-ajax.php endpoint requires a different routing structure:
- Check if the plugin uses
admin-post.phpactions. - Check for custom REST API routes:
grep -r "register_rest_route" . - If the function
postConfirmOauthrequires specific parameters (like acodeorstate), try adding dummy values:&code=123&state=abc. The goal is to trigger the logic that modifies the connection state without a nonce.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.