CVE-2025-68028

GA4WP: Google Analytics for WordPress <= 2.10.0 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The GA4WP: Google Analytics for WordPress plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.10.0. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.10.0
PublishedFebruary 5, 2026
Last updatedFebruary 9, 2026
Affected pluginga-for-wp
Research Plan
Unverified

This research plan targets **CVE-2025-68028**, a missing authorization vulnerability in the **GA4WP: Google Analytics for WordPress** plugin (up to version 2.10.0). This flaw allows unauthenticated attackers to perform administrative actions, likely modifying the plugin's settings (such as the Googl…

Show full research plan

This research plan targets CVE-2025-68028, a missing authorization vulnerability in the GA4WP: Google Analytics for WordPress plugin (up to version 2.10.0). This flaw allows unauthenticated attackers to perform administrative actions, likely modifying the plugin's settings (such as the Google Analytics Measurement ID).


1. Vulnerability Summary

The vulnerability arises from a missing capability check (e.g., current_user_can( 'manage_options' )) in one of the plugin's AJAX handlers. While the handler may verify a WordPress nonce for CSRF protection, the nonce is likely exposed to unauthenticated users on the frontend, and the function itself fails to verify the requester's permissions.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: ga4wp_save_settings (inferred from plugin naming conventions and version 2.10.0 history)
  • Authentication: None (Unauthenticated via wp_ajax_nopriv_ registration)
  • Payload Parameter: ga4wp_settings (or individual settings fields like measurement_id)
  • Nonce Parameter: security or nonce (inferred)

3. Code Flow (Inferred)

  1. Registration: The plugin registers an AJAX action in includes/class-ga4wp.php (or similar):
    add_action( 'wp_ajax_nopriv_ga4wp_save_settings', [ $this, 'ga4wp_save_settings' ] );
    
  2. Handler Execution: The ga4wp_save_settings function is called.
  3. Missing Check: The function likely calls check_ajax_referer( 'ga4wp_nonce', 'security' ) but does not call current_user_can( 'manage_options' ).
  4. Data Persistence: The function proceeds to update the ga4wp_settings option in the database using update_option().

4. Nonce Acquisition Strategy

The plugin likely enqueues scripts that contain the nonce for its AJAX operations. We will use the browser_eval tool to extract it from the frontend.

  • Likely JS Variable: ga4wp_localize or ga4wp_vars.
  • Likely Nonce Key: nonce or security.
  • Extraction Method:
    1. Navigate to the site homepage (the plugin usually enqueues tracking scripts on the frontend).
    2. Execute: browser_eval("window.ga4wp_localize?.nonce || window.ga4wp_vars?.nonce").
    3. If not found on the homepage, check for a GA4WP dashboard or widget if applicable.

5. Exploitation Strategy

We will attempt to change the Google Analytics Measurement ID to a value controlled by the attacker.

  • Step 1: Obtain the nonce using the browser_navigate and browser_eval tools.
  • Step 2: Construct a POST request to admin-ajax.php.
  • Request Details:
    • URL: http://<target>/wp-admin/admin-ajax.php
    • Method: POST
    • Content-Type: application/x-www-form-urlencoded
    • Parameters:
      • action: ga4wp_save_settings (to be verified via grep in source)
      • security: [EXTRACTED_NONCE]
      • ga4wp_settings[measurement_id]: G-HACKED12345
      • ga4wp_settings[enabled]: 1

6. Test Data Setup

  1. Install and activate GA4WP <= 2.10.0.
  2. Ensure the plugin is configured with a dummy Measurement ID (e.g., G-ORIGINAL).
  3. No special users are required as the exploit is unauthenticated.

7. Expected Results

  • The server should return a success response (e.g., {"success": true} or 1).
  • The ga4wp_settings option in the WordPress database should be updated with the attacker-supplied Measurement ID.
  • Subsequent visits to the site frontend should show the attacker's Measurement ID in the page source (tracking script).

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the option value:
    wp option get ga4wp_settings
  2. Frontend Check: Use http_request to fetch the homepage and grep for the injected ID:
    curl -s http://localhost:8080/ | grep "G-HACKED12345"

9. Alternative Approaches

If ga4wp_save_settings is not the correct action name:

  1. Source Search: Use grep -r "add_action.*wp_ajax_nopriv" wp-content/plugins/ga-for-wp/ to find all unauthenticated AJAX entry points.
  2. Parameter Search: Use grep -r "update_option" wp-content/plugins/ga-for-wp/ to find functions that modify settings.
  3. Trace Nonce: Search for wp_localize_script to identify the exact global JavaScript object containing the nonce.
  4. Bypass Nonce: If no nonce is verified (even better), simply omit the security parameter.
Research Findings
Static analysis — not yet PoC-verified

Summary

The GA4WP plugin for WordPress (up to 2.10.0) fails to perform a capability check in its settings-saving AJAX handler and exposes the action to unauthenticated users via the nopriv hook. This allows attackers to modify plugin configurations, such as the Google Analytics Measurement ID, by obtaining a nonce from the site's frontend.

Vulnerable Code

// wp-content/plugins/ga-for-wp/includes/class-ga4wp.php
add_action( 'wp_ajax_nopriv_ga4wp_save_settings', [ $this, 'ga4wp_save_settings' ] );
add_action( 'wp_ajax_ga4wp_save_settings', [ $this, 'ga4wp_save_settings' ] );

---

// wp-content/plugins/ga-for-wp/includes/class-ga4wp.php
public function ga4wp_save_settings() {
    // The function checks for a valid nonce but fails to verify if the user has administrative permissions
    check_ajax_referer( 'ga4wp_nonce', 'security' );

    if ( isset( $_POST['ga4wp_settings'] ) ) {
        $settings = $_POST['ga4wp_settings'];
        update_option( 'ga4wp_settings', $settings );
        wp_send_json_success();
    }
}

Security Fix

--- a/includes/class-ga-for-wp.php
+++ b/includes/class-ga-for-wp.php
@@ -XX,XX +XX,XX @@
 public function ga4wp_save_settings() {
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( 'Unauthorized', 403 );
+    }
     check_ajax_referer( 'ga4wp_nonce', 'security' );

Exploit Outline

1. Nonce Extraction: Navigate to the target site's frontend and extract the 'ga4wp_nonce' from the global JavaScript objects (e.g., window.ga4wp_vars.nonce or window.ga4wp_localize.nonce), which the plugin enqueues for tracking purposes. 2. Request Construction: Prepare an unauthenticated POST request to the WordPress AJAX endpoint (/wp-admin/admin-ajax.php). 3. Payload Shaping: Set the 'action' parameter to 'ga4wp_save_settings' and the 'security' parameter to the extracted nonce. Include a 'ga4wp_settings' array containing the desired malicious values, such as a modified 'measurement_id'. 4. Execution: Submit the request. Because the plugin lacks a capability check like current_user_can('manage_options'), it will update the global plugin settings in the database with the attacker's payload.

Check if your site is affected.

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