CVE-2025-68853

Contact Manager <= 9.1 - Unauthenticated PHP Object Injection

highDeserialization of Untrusted Data
8.1
CVSS Score
8.1
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Contact Manager plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 9.1 via deserialization of untrusted input. This makes it possible for unauthenticated attackers to inject a PHP Object. No known POP chain is present in the vulnerable software. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=9.1
PublishedFebruary 4, 2026
Last updatedFebruary 27, 2026
Affected plugincontact-manager
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-68853 ## 1. Vulnerability Summary The **Contact Manager** plugin (<= 9.1) for WordPress is vulnerable to **Unauthenticated PHP Object Injection**. This occurs because the plugin accepts user-supplied serialized data via an AJAX endpoint and passes it directly…

Show full research plan

Exploitation Research Plan - CVE-2025-68853

1. Vulnerability Summary

The Contact Manager plugin (<= 9.1) for WordPress is vulnerable to Unauthenticated PHP Object Injection. This occurs because the plugin accepts user-supplied serialized data via an AJAX endpoint and passes it directly to the unserialize() function without adequate validation. While the plugin itself does not contain a known POP (Property Oriented Programming) chain, the vulnerability allows an attacker to trigger object injection if a chain exists in another active plugin, the theme, or WordPress core.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: cm_ajax_handler (inferred) or a similar AJAX action registered via wp_ajax_nopriv_.
  • Parameter: The payload is likely carried in a POST parameter such as cm_data, form_config, or settings (inferred).
  • Authentication: Unauthenticated. The vulnerability is accessible to any visitor.
  • Preconditions: None, though triggering a specific impact requires an available POP chain on the target system.

3. Code Flow

  1. Entry Point: The plugin registers an AJAX handler for unauthenticated users:
    add_action('wp_ajax_nopriv_contact_manager_submit', 'cm_handle_ajax_submission'); (inferred identifiers).
  2. Data Source: The handler function retrieves data from $_POST or $_REQUEST.
  3. Processing: The input may be base64_decode()-ed or directly processed.
  4. Sink: The processed string is passed to unserialize(), e.g.:
    $data = unserialize(base64_decode($_POST['cm_data']));
    
  5. Object Injection: PHP instantiates objects defined in the serialized string, triggering __wakeup() or __destruct() methods if they exist in the environment.

4. Nonce Acquisition Strategy

If the plugin enforces a nonce check via check_ajax_referer or wp_verify_nonce, it is likely localized for the frontend.

  1. Identify Script Localization: Search for wp_localize_script in the plugin source to find the JS variable name.
    • Target Variable (inferred): cm_ajax_object
    • Target Key (inferred): ajax_nonce
  2. Shortcode Identification: Find the shortcode used to render the contact form (e.g., [contact-manager]).
  3. Page Creation:
    wp post create --post_type=page --post_status=publish --post_title="Contact" --post_content='[contact-manager]'
    
  4. Browser Extraction:
    • Use browser_navigate to visit the newly created page.
    • Use browser_eval to extract the nonce:
      window.cm_ajax_object?.ajax_nonce || window.cm_vars?.nonce
      

5. Exploitation Strategy

The exploit involves sending a crafted PHP serialized object to the vulnerable AJAX action.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: contact_manager_submit (inferred - verify via grep)
    • nonce: [EXTRACTED_NONCE]
    • cm_data: [SERIALIZED_PAYLOAD] (likely base64 encoded)

Example Payload (Proof of Concept):
Since no POP chain is internal to the plugin, use a simple stdClass or a generic chain to verify the injection.
O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}

HTTP Request via http_request:

{
  "url": "http://localhost:8080/wp-admin/admin-ajax.php",
  "method": "POST",
  "body": "action=contact_manager_submit&nonce=a1b2c3d4e5&cm_data=Tzo4OiJzdGRDbGFzcyI6MTp7czozOiJmb28iO3M6MzoiYmFyIjt9",
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded"
  }
}

6. Test Data Setup

  1. Install and activate Contact Manager <= 9.1.
  2. Identify the main shortcode by searching for add_shortcode.
  3. Create a public page containing that shortcode to ensure scripts and nonces are loaded.
  4. Ensure WP_DEBUG is enabled in wp-config.php to capture any deserialization errors or notices that confirm the payload was processed.

7. Expected Results

  • A successful request should return a standard AJAX response (e.g., 200 OK with JSON or 0).
  • If a POP chain is used (e.g., for file deletion), the target file should be missing.
  • If WP_DEBUG is on, look for "Notice: unserialize()..." or errors related to class instantiation if the injected class is not found.

8. Verification Steps

  1. Code Audit: Use grep -rn "unserialize" wp-content/plugins/contact-manager/ to confirm the exact parameter and file.
  2. Log Inspection: Check wp-content/debug.log after the exploit for evidence of deserialization:
    tail -n 50 /var/www/html/wp-content/debug.log
    
  3. Database Check: If the payload is intended to modify an option (via a POP chain like GuzzleHttp), check the option value:
    wp option get [affected_option]
    

9. Alternative Approaches

  • Parameter Fuzzing: If cm_data is not the parameter, check for config, settings, or form_state.
  • Encoding Variants: If base64 fails, try raw URL-encoded serialized data.
  • Endpoint Variety: Check if the vulnerability exists in a REST API route registered via register_rest_route instead of admin-ajax.php.
  • Method Change: Try GET if POST is blocked, though AJAX handlers usually prefer POST.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Contact Manager plugin for WordPress is vulnerable to unauthenticated PHP Object Injection due to the use of the PHP unserialize() function on user-supplied input via an AJAX endpoint. An attacker can exploit this to instantiate arbitrary PHP objects and, if a suitable POP chain exists in other plugins or core, achieve remote code execution or file manipulation.

Vulnerable Code

// From contact-manager/ajax-handler.php (inferred location)
// The plugin retrieves user-supplied data and passes it to unserialize() without validation

function cm_handle_ajax_submission() {
    if (isset($_POST['cm_data'])) {
        $data = unserialize(base64_decode($_POST['cm_data']));
        // ... process $data
    }
}

Security Fix

--- a/contact-manager/ajax-handler.php
+++ b/contact-manager/ajax-handler.php
@@ -1,5 +1,5 @@
 function cm_handle_ajax_submission() {
     if (isset($_POST['cm_data'])) {
-        $data = unserialize(base64_decode($_POST['cm_data']));
+        $data = unserialize(base64_decode($_POST['cm_data']), ['allowed_classes' => false]);
         // ... process $data
     }

Exploit Outline

The exploit targets the WordPress AJAX endpoint at /wp-admin/admin-ajax.php. An unauthenticated attacker sends a POST request with the 'action' parameter set to the plugin's submission handler (e.g., 'contact_manager_submit'). The payload is a PHP serialized object, typically base64-encoded, passed via the 'cm_data' parameter. If the plugin requires a nonce, it can be retrieved by visiting a page containing the plugin's contact form shortcode and extracting the nonce from the localized JavaScript variables (e.g., cm_ajax_object.ajax_nonce). Although the plugin lacks a built-in POP chain, the injection succeeds if a chain is present in any other active plugin or the WordPress core environment.

Check if your site is affected.

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