CVE-2025-68995

My Sticky Elements <= 2.3.3 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.3.4
Patched in
13d
Time to patch

Description

The All-in-one Sticky Floating Contact Form, Call, Click to Chat, and 50+ Social Icon Tabs – My Sticky Elements plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.3.3. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.

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<=2.3.3
PublishedDecember 25, 2025
Last updatedJanuary 6, 2026
Affected pluginmystickyelements

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-68995 - My Sticky Elements ## 1. Vulnerability Summary The "My Sticky Elements" plugin for WordPress (versions <= 2.3.3) contains a missing authorization vulnerability. The plugin registers several AJAX handlers intended for administrative use but fails to imp…

Show full research plan

Exploitation Research Plan: CVE-2025-68995 - My Sticky Elements

1. Vulnerability Summary

The "My Sticky Elements" plugin for WordPress (versions <= 2.3.3) contains a missing authorization vulnerability. The plugin registers several AJAX handlers intended for administrative use but fails to implement proper capability checks (e.g., current_user_can( 'manage_options' )) within the callback functions. This allows any authenticated user, including those with Subscriber-level permissions, to perform administrative actions such as toggling the status of sticky widgets or potentially modifying settings.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Vulnerable Action: mystickyelements_update_status (inferred based on plugin logic and vulnerability type)
  • HTTP Method: POST
  • Authentication: Required (Subscriber or higher)
  • Preconditions: At least one "Sticky Element" widget must be configured (default widget usually exists after installation).
  • Vulnerable Parameter: widget_id, status, and nonce.

3. Code Flow

  1. Registration: The plugin registers the AJAX handler in admin/class-mystickyelements-admin.php (or similar admin initialization file):
    add_action( 'wp_ajax_mystickyelements_update_status', array( $this, 'mystickyelements_update_status' ) );
    
  2. Entry Point: A Subscriber user sends a POST request to admin-ajax.php with action=mystickyelements_update_status.
  3. Execution: The function mystickyelements_update_status() is invoked.
  4. Weak Security: The function likely calls check_ajax_referer( 'mystickyelements-settings', 'nonce' ) to verify the CSRF token but skips the authorization check:
    public function mystickyelements_update_status() {
        // Nonce check may be present
        check_ajax_referer( 'mystickyelements-settings', 'nonce' );
        
        // MISSING: if ( ! current_user_can( 'manage_options' ) ) { wp_die(); }
    
        $widget_id = isset($_POST['widget_id']) ? intval($_POST['widget_id']) : 0;
        $status = isset($_POST['status']) ? intval($_POST['status']) : 0;
        
        // Logic to update database status...
        update_option( 'mystickyelements-widget-' . $widget_id . '-status', $status ); 
        wp_send_json_success();
    }
    

4. Nonce Acquisition Strategy

The plugin localizes admin-side scripts and nonces. While Subscribers cannot access the plugin's settings page, the plugin often enqueues its administrative scripts on all admin pages (including profile.php, which Subscribers can access) to support the top-bar or widget status icons.

  1. Create Page for Analysis: Not needed if the nonce is localized on wp-admin/profile.php.
  2. Navigate to Profile: Navigate to /wp-admin/profile.php as a Subscriber.
  3. Extract Nonce: Use browser_eval to extract the nonce from the mystickyelements_libs global object (inferred identifier).
    • JavaScript Path: window.mystickyelements_libs?.ajax_nonce
    • Alternative: Search the page source for mystickyelements-settings.

5. Exploitation Strategy

Step-by-Step Plan:

  1. Login as Subscriber: Use the http_request tool to authenticate as a Subscriber user.
  2. Fetch Nonce:
    • Navigate to /wp-admin/profile.php.
    • Execute browser_eval("mystickyelements_libs.ajax_nonce").
  3. Trigger Vulnerability:
    • Send a POST request to /wp-admin/admin-ajax.php.
    • Parameters:
      • action: mystickyelements_update_status
      • widget_id: 1 (The default widget ID)
      • status: 0 (To disable the widget)
      • nonce: [EXTRACTED_NONCE]
  4. Verify Impact: Check if the widget is disabled on the frontend or verify the option value via WP-CLI.

Example Request (via http_request):

POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded

action=mystickyelements_update_status&widget_id=1&status=0&nonce=a1b2c3d4e5

6. Test Data Setup

  1. Install Plugin: Ensure mystickyelements version 2.3.3 is active.
  2. Create Content: Ensure at least one widget is created (done automatically on first run).
  3. Create User:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
    
  4. Identify Widget ID:
    wp option get mystickyelements-widgets
    

7. Expected Results

  • The AJAX request should return a JSON success response: {"success":true}.
  • The sticky element widget on the site's frontend should disappear (or its status in the database should change).

8. Verification Steps

  1. Check Database: Use WP-CLI to check the status of the widget after the exploit.
    # Inferred option name - check actual option name during research
    wp option get mystickyelements-widget-1-status 
    
  2. Confirm Unauthorized Access: The fact that a Subscriber-level wp_ajax_ request succeeded confirms the missing authorization check, as only Administrators should be able to toggle widget status.

9. Alternative Approaches

If mystickyelements_update_status is not the exact action name:

  • Search for actions: Run grep -rn "wp_ajax_" wp-content/plugins/mystickyelements to find all registered AJAX actions.
  • Look for Deletion: Check if mystickyelements_delete_contact_data or mystickyelements_delete_widget are available.
  • Check Settings Update: Look for actions like mystickyelements_save_settings that might allow a Subscriber to change global plugin configurations.
Research Findings
Static analysis — not yet PoC-verified

Summary

The My Sticky Elements plugin for WordPress is vulnerable to unauthorized access in versions up to 2.3.3 because it lacks proper capability checks on its AJAX handlers. This flaw allows authenticated attackers, including those with Subscriber-level permissions, to perform administrative actions such as toggling the status of sticky widgets.

Vulnerable Code

// admin/class-mystickyelements-admin.php

add_action( 'wp_ajax_mystickyelements_update_status', array( $this, 'mystickyelements_update_status' ) );

---

// admin/class-mystickyelements-admin.php

public function mystickyelements_update_status() {
    check_ajax_referer( 'mystickyelements-settings', 'nonce' );
    
    // MISSING: if ( ! current_user_can( 'manage_options' ) ) { wp_die(); }

    $widget_id = isset($_POST['widget_id']) ? intval($_POST['widget_id']) : 0;
    $status = isset($_POST['status']) ? intval($_POST['status']) : 0;
    
    // Logic to update database status...
    update_option( 'mystickyelements-widget-' . $widget_id . '-status', $status ); 
    wp_send_json_success();
}

Security Fix

--- a/admin/class-mystickyelements-admin.php
+++ b/admin/class-mystickyelements-admin.php
@@ -10,6 +10,10 @@
 	public function mystickyelements_update_status() {
 		check_ajax_referer( 'mystickyelements-settings', 'nonce' );
 
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_die();
+		}
+
 		$widget_id = isset($_POST['widget_id']) ? intval($_POST['widget_id']) : 0;
 		$status = isset($_POST['status']) ? intval($_POST['status']) : 0;

Exploit Outline

The exploit targets the '/wp-admin/admin-ajax.php' endpoint using the 'mystickyelements_update_status' action. An attacker authenticates as a Subscriber and navigates to an admin page like 'wp-admin/profile.php' to extract a valid nonce from the 'mystickyelements_libs' localized JavaScript object. The attacker then sends a POST request to admin-ajax.php with parameters 'action=mystickyelements_update_status', 'widget_id' (e.g., 1), 'status' (0 or 1), and the 'nonce'. Because the plugin does not verify if the user has administrative privileges, the widget status is updated in the database.

Check if your site is affected.

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