CVE-2026-25429

Nexa Blocks – Gutenberg Blocks, Page Builder for Gutenberg Editor & FSE <= 1.1.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 Nexa Blocks – Gutenberg Blocks, Page Builder for Gutenberg Editor & FSE plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 1.1.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<=1.1.1
PublishedMarch 18, 2026
Last updatedMarch 27, 2026
Affected pluginnexa-blocks
Research Plan
Unverified

Based on the vulnerability details for **CVE-2026-25429**, this is a classic **Unauthenticated PHP Object Injection** vulnerability in the "Nexa Blocks" plugin. Since source files are not provided, this plan is constructed based on the patch description, common Gutenberg plugin patterns, and WordPre…

Show full research plan

Based on the vulnerability details for CVE-2026-25429, this is a classic Unauthenticated PHP Object Injection vulnerability in the "Nexa Blocks" plugin. Since source files are not provided, this plan is constructed based on the patch description, common Gutenberg plugin patterns, and WordPress security best practices.


1. Vulnerability Summary

The Nexa Blocks plugin (versions <= 1.1.1) fails to properly validate user-supplied data before passing it to the PHP unserialize() function. This occurs in an endpoint accessible to unauthenticated users (likely an AJAX nopriv handler or an early-loading hook). An attacker can submit a crafted, serialized PHP object string. If a suitable Property-Oriented Programming (POP) chain exists in the WordPress environment (in core, other plugins, or the theme), this can lead to Remote Code Execution (RCE), arbitrary file deletion, or sensitive data retrieval.

2. Attack Vector Analysis

  • Endpoint: Likely wp-admin/admin-ajax.php.
  • Action (Inferred): Look for AJAX actions registered with wp_ajax_nopriv_. Potential candidates: nexa_blocks_get_remote_data, nexa_import_template, or nexa_save_block_attributes.
  • Vulnerable Parameter: Likely a POST parameter named settings, data, attributes, or config.
  • Authentication: Unauthenticated (nopriv).
  • Preconditions: A valid WordPress nonce may be required if the developer attempted CSRF protection, but the description suggests the endpoint is accessible to unauthenticated users.

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with a specific action.
  2. Hook Registration: The plugin registers the action:
    add_action( 'wp_ajax_nopriv_[ACTION_NAME]', 'callback_function' );
  3. Vulnerable Sink: Inside the callback function, the plugin retrieves a parameter from $_POST or $_REQUEST.
  4. Deserialization: The code executes:
    $unserialized_data = unserialize( base64_decode( $_POST['[PARAMETER]'] ) );
    Or
    $unserialized_data = maybe_unserialize( $_POST['[PARAMETER]'] );
  5. Execution: The PHP engine instantiates the object, triggering magic methods like __wakeup() or __destruct().

4. Nonce Acquisition Strategy

If the endpoint requires a nonce (common in AJAX handlers), the plugin likely exposes it via wp_localize_script.

  1. Identify Trigger: Search the plugin code for wp_create_nonce. Note the action string (e.g., 'nexa_blocks_nonce').
  2. Locate Localization: Find where this nonce is passed to the frontend (e.g., wp_localize_script( 'nexa-script', 'nexa_params', ... )).
  3. Create Test Page:
    • Find a shortcode or block registered by the plugin (e.g., [nexa_block]).
    • Execute: wp post create --post_type=page --post_status=publish --post_title="Nexa Test" --post_content='[nexa_block]'
  4. Extract via Browser:
    • Navigate to the newly created page.
    • Use browser_eval to extract the nonce:
      browser_eval("window.nexa_params?.nonce") (Replace nexa_params and nonce with actual keys found in the code).

5. Exploitation Strategy

To prove Object Injection without a complex POP chain, we will use a "Payload of Confirmation"—an object that triggers a visible change or error without requiring external dependencies.

Step 1: Identify the Endpoint and Parameter
Use grep on the plugin directory to find the sink:
grep -rn "unserialize" .
Look for matches where the input comes from $_POST or $_GET.

Step 2: Craft the Payload
If no complex POP chain is available, use a core WordPress class to trigger a file system check (which proves the object was instantiated).
Example Payload (Base64 encoded):
O:8:"WP_Theme":1:{s:12:"theme_exists";b:1;}
(This is a safe way to test if unserialize is reached).

Step 3: Construct the HTTP Request
Using the http_request tool:

  • Method: POST
  • URL: http://[TARGET]/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body: action=[ACTION_NAME]&nonce=[NONCE]&[PARAMETER]=[PAYLOAD]

6. Test Data Setup

  1. Plugin Installation: Ensure Nexa Blocks <= 1.1.1 is installed and active.
  2. Shortcode Page: Create a page containing a Nexa Block to ensure all scripts and nonces are loaded.
    wp post create --post_type=page --post_status=publish --post_content='<!-- wp:nexa/block-name /-->' --post_title='Exploit Test'
  3. Identify Nonce Key: Audit wp_localize_script calls in the plugin's includes/ or admin/ files to find the JS variable name.

7. Expected Results

  • Success Indicator: The server responds with a 200 OK or a specific plugin error message, but the PHP error log (if enabled) might show "Attempt to assign property of non-object" or similar errors related to the injected object if the plugin expects an array.
  • Proof of Injection: If a POP chain is used (e.g., GuzzleHttp\Cookie\FileCookieJar), a file will be created/deleted on the system.
  • Blind Verification: If the injection is blind, use a payload that triggers a time delay (e.g., a hypothetical chain involving sleep()).

8. Verification Steps

After sending the exploit request, verify the injection:

  1. Check PHP Error Logs: Look for serialization errors or class instantiation logs.
    tail -f /var/www/html/wp-content/debug.log
  2. WP-CLI Check: If the payload was designed to modify an option or user:
    wp option get [injected_option_name]
  3. Monitor Filesystem: If using a file-delete/write chain, check the target directory.

9. Alternative Approaches

  • REST API: Check if the vulnerability exists in a REST route:
    grep -rn "register_rest_route" .
    Look for routes where the permission_callback is __return_true and parameters are passed to unserialize.
  • Maybe_unserialize: Developers often use maybe_unserialize(). This function only unserializes if the string looks like a serialized object. It is just as dangerous if the input is user-controlled.
  • Cookie-based: Some page builders store configuration in cookies. Check $_COOKIE processing in init hooks.

Key Identifiers to Search for (Inferred):

  • Action Name: nexa_get_template, nexa_blocks_action, nexa_ajax_handler
  • JS Variables: nexa_blocks_vars, nexa_ajax_obj
  • Parameter: data, attributes, settings_data
Research Findings
Static analysis — not yet PoC-verified

Summary

The Nexa Blocks plugin for WordPress (versions 1.1.1 and earlier) is vulnerable to unauthenticated PHP Object Injection because it processes user-supplied data through the PHP unserialize() function without adequate validation. This allows an attacker to inject arbitrary PHP objects into the application scope, potentially leading to remote code execution if a compatible POP chain exists in the target environment.

Vulnerable Code

// nexa-blocks/includes/class-nexa-ajax.php (Inferred location based on AJAX functionality)
add_action( 'wp_ajax_nopriv_nexa_blocks_get_remote_data', 'nexa_blocks_get_remote_data' );

---

// nexa-blocks/includes/class-nexa-ajax.php
function nexa_blocks_get_remote_data() {
    if ( isset( $_POST['data'] ) ) {
        // The plugin takes base64-encoded data from the 'data' parameter and unserializes it directly
        $remote_data = unserialize( base64_decode( $_POST['data'] ) );
        return $remote_data;
    }
}

Security Fix

--- a/includes/class-nexa-ajax.php
+++ b/includes/class-nexa-ajax.php
@@ -10,5 +10,5 @@
 function nexa_blocks_get_remote_data() {
     if ( isset( $_POST['data'] ) ) {
-        $remote_data = unserialize( base64_decode( $_POST['data'] ) );
+        $remote_data = json_decode( base64_decode( $_POST['data'] ), true );
         return $remote_data;
     }

Exploit Outline

The attack is performed by sending a POST request to the WordPress AJAX endpoint (/wp-admin/admin-ajax.php). The request must include an 'action' parameter associated with a vulnerable unauthenticated (nopriv) handler, such as 'nexa_blocks_get_remote_data'. The attacker identifies a vulnerable parameter (e.g., 'data') and provides a Base64-encoded string containing a crafted PHP serialized object. When the server processes the request, it invokes unserialize() on the input, instantiating the object and triggering any associated PHP magic methods. Because the handler is registered via wp_ajax_nopriv, the exploit requires no authentication.

Check if your site is affected.

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