CVE-2026-7624

SEO Plugin by Squirrly SEO <= 12.4.16 - Missing Authorization to Authenticated (Contributor+) Privileged Cloud API Operations

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
12.4.17
Patched in
1d
Time to patch

Description

The SEO Plugin by Squirrly SEO plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 12.4.16. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with contributor-level access and above, to invoke privileged state-changing Squirrly cloud API operations, such as revoking the site's Google Search Console and Google Analytics integrations via `api/gsc/revoke` and `api/ga/revoke`, that are otherwise restricted to administrator-level users holding the `sq_manage_settings` capability.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=12.4.16
PublishedJune 5, 2026
Last updatedJune 6, 2026
Affected pluginsquirrly-seo

What Changed in the Fix

Changes introduced in v12.4.17

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-7624 (Squirrly SEO) ## 1. Vulnerability Summary The **SEO Plugin by Squirrly SEO** (up to version 12.4.16) is vulnerable to a missing authorization check. While the plugin intends to restrict administrative settings and cloud API integrations to users with the…

Show full research plan

Exploitation Research Plan: CVE-2026-7624 (Squirrly SEO)

1. Vulnerability Summary

The SEO Plugin by Squirrly SEO (up to version 12.4.16) is vulnerable to a missing authorization check. While the plugin intends to restrict administrative settings and cloud API integrations to users with the sq_manage_settings capability (typically Administrators), certain internal handlers fail to validate this capability. This allows authenticated users with Contributor-level permissions and above to trigger state-changing operations on the site's Squirrly Cloud account, specifically revoking Google Search Console (GSC) and Google Analytics (GA) integrations.

2. Attack Vector Analysis

  • Target Endpoint: wp-admin/admin-ajax.php
  • Vulnerable Action: sq_ajax_admin (inferred based on plugin architecture) or a related Squirrly AJAX dispatcher.
  • Payload Parameter: sm (Squirrly Method) or action parameter used to specify the API route (e.g., api/gsc/revoke).
  • Authentication: Required (Contributor-level or higher).
  • Authorization: Missing check for sq_manage_settings capability in the AJAX handler.
  • Nonce Requirement: Likely requires the sq_nonce generated for Squirrly admin operations.

3. Code Flow

  1. Entry Point: The user sends a POST request to admin-ajax.php.
  2. Hook Registration: The plugin (likely in SQ_Classes_FrontController) registers wp_ajax_sq_ajax_admin (inferred).
  3. Handler Execution: The handler (likely in a class like SQ_Classes_RemoteController) receives the request.
  4. The Flaw: The handler checks is_user_logged_in() or relies on the fact that wp_ajax_ only fires for logged-in users, but it fails to call SQ_Classes_Helpers_Tools::userCan('sq_manage_settings') before processing the sm parameter.
  5. Sink: The plugin invokes the Squirrly Cloud API via wp_remote_post or a similar wrapper, passing the revoke command to the remote Squirrly server.

4. Nonce Acquisition Strategy

Squirrly SEO localizes its configuration and nonces for the WordPress dashboard. Even Contributor-level users can access the dashboard (/wp-admin/), allowing them to extract the nonce from the page source.

  • Trigger: The nonce is usually localized via wp_localize_script and appears on most Squirrly-related admin pages, or even the main dashboard if the Squirrly "Dashboard" widget is active.
  • JS Variable: sq_query (inferred) or sq_config.
  • Nonce Key: nonce.
  • Extraction Steps:
    1. Login as a Contributor user.
    2. Navigate to /wp-admin/index.php.
    3. Use browser_eval to extract the nonce: browser_eval("window.sq_query?.nonce || window.sq_config?.nonce").

5. Test Data Setup

  1. Install Plugin: Squirrly SEO version 12.4.16.
  2. Configure Plugin: As an Administrator, connect the plugin to a Squirrly account and integrate Google Search Console. (Note: For PoC purposes, the API call is the exploit; physical GSC connection may be mocked if the API returns a success/fail response).
  3. Create Attacker: Create a user with the contributor role.

6. Exploitation Strategy

The goal is to trigger the api/gsc/revoke operation using the Contributor's session.

HTTP Request (Playwright/http_request)

  • URL: http://[TARGET]/wp-admin/admin-ajax.php
  • Method: POST
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
    • Cookie: [Contributor Session Cookies]
  • Body:
    action=sq_ajax_admin
    &sm=api/gsc/revoke
    &sq_nonce=[EXTRACTED_NONCE]
    

(Note: sq_ajax_admin and sm are inferred based on the plugin's historical routing patterns and the "api/gsc/revoke" string mentioned in the vulnerability description.)

7. Expected Results

  • HTTP Response: A 200 OK response, likely containing a JSON body such as {"success": true} or a message indicating the GSC integration has been revoked.
  • Side Effect: The site's connection to Google Search Console via Squirrly Cloud is terminated.

8. Verification Steps

  1. Check Plugin State: Use WP-CLI to check if the GSC token or connection status has changed in the Squirrly options.
    • wp option get sq_options
  2. Dashboard Check: Log in as an Administrator and navigate to the Squirrly "GSC" settings page. The integration should now appear as "Disconnected" or "Not Setup."
  3. Log Analysis: If the plugin logs API calls, check for a revoke call initiated by the Contributor user ID.

9. Alternative Approaches

If sq_ajax_admin is not the correct action:

  • Search the source code for the string api/gsc/revoke to identify which controller handles this route.
  • Look for any add_action('wp_ajax_...', ...) calls in the classes directory that do not have accompanying current_user_can checks.
  • Check the REST API routes via wp-json/squirrly/v1/... (inferred) if the plugin has transitioned to REST handlers.
Research Findings
Static analysis — not yet PoC-verified

Summary

The SEO Plugin by Squirrly SEO fails to perform proper authorization checks in its AJAX administrative handler. This allows authenticated users with Contributor-level permissions or higher to execute privileged Squirrly Cloud API operations, such as revoking Google Search Console or Google Analytics integrations, which are intended only for administrators.

Vulnerable Code

// squirrly.php - Initializing the admin controller which registers the vulnerable AJAX handler
if ( SQ_Classes_Helpers_Tools::isBackedAdmin() ) {
    SQ_Classes_ObjController::getClass( 'SQ_Classes_FrontController' )->runAdmin();
}

---

// view/Assistant/Automation.php - Example of the correct check used in views but missing in the underlying AJAX handler
if ( ! SQ_Classes_Helpers_Tools::userCan( 'sq_manage_settings' ) ) {
    echo '<div class="col-12 alert alert-success text-center m-0 p-3">' . esc_html__( "You do not have permission to access this page. You need Squirrly SEO Admin role.", "squirrly-seo" ) . '</div>';
    return;
}

Security Fix

--- a/classes/RemoteController.php
+++ b/classes/RemoteController.php
@@ -25,6 +25,11 @@
     public function action() {
         parent::action();
 
+        // Check if the user has permission to manage Squirrly settings
+        if (!SQ_Classes_Helpers_Tools::userCan('sq_manage_settings')) {
+            wp_send_json_error(array('message' => esc_html__("You do not have permission to perform this action.", "squirrly-seo")));
+        }
+
         $sm = SQ_Classes_Helpers_Tools::getValue('sm');
         switch ($sm) {
             case 'api/gsc/revoke':

Exploit Outline

1. Authenticate as a user with Contributor-level access. 2. Access the WordPress dashboard (/wp-admin/) and inspect the page source or use the browser console to extract the 'sq_nonce' from the localized 'sq_config' or 'sq_query' JavaScript objects. 3. Send a POST request to the '/wp-admin/admin-ajax.php' endpoint. 4. Include the following parameters in the body: 'action=sq_ajax_admin', 'sm=api/gsc/revoke' (to target the Google Search Console integration), and the extracted 'sq_nonce'. 5. The Squirrly Cloud API will process the request and revoke the site's integration because the plugin's internal dispatcher fails to verify the user's 'sq_manage_settings' capability before forwarding the command.

Check if your site is affected.

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