CVE-2026-1426

Advanced AJAX Product Filters <= 3.1.9.6 - Authenticated (Author+) PHP Object Injection via Live Composer Compatibility

highDeserialization of Untrusted Data
8.8
CVSS Score
8.8
CVSS Score
high
Severity
3.1.9.7
Patched in
2d
Time to patch

Description

The Advanced AJAX Product Filters plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 3.1.9.6 via deserialization of untrusted input in the shortcode_check function within the Live Composer compatibility layer. This makes it possible for authenticated attackers, with Author-level access and above, to inject a PHP Object. No known POP chain is present in the vulnerable software, which means this vulnerability has no impact unless another plugin or theme containing a POP chain is installed on the site. If a POP chain is present via an additional plugin or theme installed on the target system, it may allow the attacker to perform actions like delete arbitrary files, retrieve sensitive data, or execute code depending on the POP chain present. Note: This vulnerability requires the Live Composer plugin to also be installed and active.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.1.9.6
PublishedFebruary 17, 2026
Last updatedFebruary 18, 2026

What Changed in the Fix

Changes introduced in v3.1.9.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-1426 - PHP Object Injection ## 1. Vulnerability Summary The **Advanced AJAX Product Filters** plugin (<= 3.1.9.6) contains a PHP Object Injection vulnerability due to the use of `unserialize()` on untrusted input. The vulnerability exists within the `shortcode…

Show full research plan

Exploitation Research Plan: CVE-2026-1426 - PHP Object Injection

1. Vulnerability Summary

The Advanced AJAX Product Filters plugin (<= 3.1.9.6) contains a PHP Object Injection vulnerability due to the use of unserialize() on untrusted input. The vulnerability exists within the shortcode_check function of the BeRocket_AAPF_compat_live_composer_builder class, which handles compatibility with the Live Composer page builder. When a specific shortcode (dslc_module_posts_output) is processed, the plugin attempts to deserialize the content inside the shortcode to extract configuration settings. An authenticated attacker with Author level permissions or higher can create a post containing this shortcode and inject a malicious serialized PHP object.

2. Attack Vector Analysis

  • Endpoint: Frontend post/page rendering.
  • Trigger: The vulnerability is triggered via the pre_do_shortcode_tag filter hook.
  • Hook Registration: add_filter('pre_do_shortcode_tag', array($this, 'shortcode_check'), 10, 5); in includes/compatibility/live_composer.php.
  • Payload Placement: The malicious object is placed inside the content area of the [dslc_module_posts_output] shortcode.
  • Authentication: Required (Author+). Authors have the capability to create and publish posts (edit_posts, publish_posts).
  • Precondition: The Live Composer plugin must be installed and active.

3. Code Flow

  1. Entry Point: A user with Author+ permissions saves or previews a post containing the shortcode: [dslc_module_posts_output]{PAYLOAD}[/dslc_module_posts_output].
  2. Filter Execution: When WordPress renders the post, do_shortcode() calls the pre_do_shortcode_tag filter.
  3. Vulnerable Function: BeRocket_AAPF_compat_live_composer_builder::shortcode_check($content, $tag, $attr, $m) is executed.
  4. Tag Verification: The function checks if $tag == 'dslc_module_posts_output'.
  5. Extraction: The variable $args is populated from $m[5], which represents the inner content of the shortcode.
  6. Sinks:
    • includes/compatibility/live_composer.php:26: $data = @unserialize( $args );
    • includes/compatibility/live_composer.php:29: $options = unserialize( $args ); (if the first check passes).
    • includes/compatibility/live_composer.php:34: $options = unserialize( $fixed_data ); (if the first check fails but the regex fixup works).

4. Nonce Acquisition Strategy

This vulnerability is triggered during post rendering, not via a specific AJAX action. To inject the payload, the attacker must create a post.

  1. Capability: Authenticated as Author.
  2. Method: Use the WordPress REST API to create a post.
  3. Nonce Requirement: The REST API requires a _wpnonce in the X-WP-Nonce header.
  4. Acquisition:
    • Navigate to /wp-admin/ or any dashboard page.
    • Execute browser_eval("window.wpApiSettings?.nonce") to retrieve the REST API nonce.
    • If the REST API is restricted, the attacker can use the classic editor (requires a _wpnonce and _wp_http_referer from the post-new.php page).

5. Exploitation Strategy

Step 1: Pre-requisite Setup

  1. Ensure "Live Composer" (slug: live-composer-page-builder) is active.
  2. Ensure "Advanced AJAX Product Filters" is active.

Step 2: Payload Construction

Since there is no known POP chain in the target plugin, use a PHP object that triggers a recognizable side effect (e.g., a class that doesn't exist to trigger a PHP error, or a core WP class if available).

  • PoC Payload: O:8:"stdClass":0:{}
  • Wrapped Payload: [dslc_module_posts_output]O:8:"stdClass":0:{}[/dslc_module_posts_output]

Step 3: Injection (Post Creation)

Submit the payload via the REST API.

  • Method: POST
  • URL: /wp-json/wp/v2/posts
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: [EXTRACTED_NONCE]
  • Body:
{
    "title": "Exploit Test",
    "content": "[dslc_module_posts_output]O:8:\"stdClass\":0:{}[/dslc_module_posts_output]",
    "status": "publish"
}

Step 4: Triggering the Sink

Visit the newly created post URL.

  • Method: GET
  • URL: /?p=[CREATED_POST_ID]
  • Action: The server processes the shortcode, triggering shortcode_check, and executes unserialize() on the stdClass object.

6. Test Data Setup

  1. User: Create a user with the Author role.
    • wp user create attacker attacker@example.com --role=author --user_pass=password
  2. Plugin Configuration: No specific AAPF configuration is required, as the Live Composer compatibility layer loads automatically.

7. Expected Results

  • A successful exploit (in a research/debugging context) will manifest as the PHP interpreter attempting to instantiate the serialized object.
  • If using an invalid class like O:21:"BeRocket_Exploit_Test":0:{}, the exploit can be verified by checking for an "PHP Notice: unserialize(): Error at offset..." or checking if a __wakeup or __destruct method would have fired if a POP chain existed.
  • The shortcode_check function will proceed to check $options['bapf_apply'] which will fail silently if an object was passed instead of an array, confirming the code path was reached.

8. Verification Steps

  1. Check Post Content:
    • wp post get [POST_ID] --field=content
    • Confirm the shortcode and payload are stored exactly as sent.
  2. Monitor Logs:
    • Monitor wp-content/debug.log while visiting the post.
    • Look for unserialize() related errors or class instantiation attempts if using a custom payload.

9. Alternative Approaches

If the REST API is disabled:

  1. Navigate to wp-admin/post-new.php.
  2. Extract the _wpnonce from the form using browser_eval("jQuery('#_wpnonce').val()").
  3. Submit a standard multipart/form-data POST request to wp-admin/post.php to save the post.
  4. Proceed to Step 4 of the Exploitation Strategy.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Advanced AJAX Product Filters plugin for WordPress is vulnerable to PHP Object Injection in versions up to 3.1.9.6. This occurs via the use of the PHP unserialize() function on user-supplied content within the [dslc_module_posts_output] shortcode when the Live Composer compatibility layer is active. Authenticated attackers with Author-level access or higher can exploit this to inject PHP objects, potentially leading to remote code execution if a suitable POP chain is present in other installed plugins or the theme.

Vulnerable Code

// includes/compatibility/live_composer.php:22
function shortcode_check($content, $tag, $attr, $m) {
    if( 'dslc_module_posts_output' == $tag && is_array($m) && ! empty($m[5]) ) {
        $args = $m[5];
        $data = @unserialize( $args );

        if ( $data !== false ) {
            $options = unserialize( $args );
        } else {
            $fixed_data = preg_replace_callback( '!s:(\d+):"(.*?)";!', function( $match ) {
                return ( $match[1] == strlen( $match[2] ) ) ? $match[0] : 's:' . strlen( $match[2] ) . ':"' . $match[2] . '";';
            }, $args );
            $options = unserialize( $fixed_data );
        }

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/woocommerce-ajax-filters/3.1.9.6/includes/compatibility/live_composer.php	2026-01-13 14:08:16.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/woocommerce-ajax-filters/3.1.9.7/includes/compatibility/live_composer.php	2026-01-29 08:22:14.000000000 +0000
@@ -21,27 +21,29 @@
         }
         function shortcode_check($content, $tag, $attr, $m) {
             if( 'dslc_module_posts_output' == $tag && is_array($m) && ! empty($m[5]) ) {
-                $args = $m[5];
-                $data = @unserialize( $args );
+                try {
+                    $args = $m[5];
+                    $data = json_decode( $args, true );
 
-                if ( $data !== false ) {
-                    $options = unserialize( $args );
-                } else {
-                    $fixed_data = preg_replace_callback( '!s:(\d+):"(.*?)";!', function( $match ) {
-                        return ( $match[1] == strlen( $match[2] ) ) ? $match[0] : 's:' . strlen( $match[2] ) . ':"' . $match[2] . '";';
-                    }, $args );
-                    $options = unserialize( $fixed_data );
-                }
-                $bapf_status = ( isset($options['bapf_apply']) ? $options['bapf_apply'] : false );
-                $enabled = braapf_is_shortcode_must_be_filtered();
-                if( $bapf_status !== false ) {
-                    if( $bapf_status == 'enable' ) {
-                        $enabled = true;
-                    } elseif( $bapf_status == 'disable' ) {
-                        $enabled = false;
+                    if ( $data !== false ) {
+                        $options = $data;
+                    } else {
+                        $fixed_data = preg_replace_callback( '!s:(\d+):"(.*?)";!', function( $match ) {
+                            return ( $match[1] == strlen( $match[2] ) ) ? $match[0] : 's:' . strlen( $match[2] ) . ':"' . $match[2] . '";';
+                        }, $args );
+                        $options = json_decode( $fixed_data, true );
                     }
-                }
-                do_action('brapf_next_shortcode_apply_action', array('apply' => $enabled));
+                    $bapf_status = ( isset($options['bapf_apply']) ? $options['bapf_apply'] : false );
+                    $enabled = braapf_is_shortcode_must_be_filtered();
+                    if( $bapf_status !== false ) {
+                        if( $bapf_status == 'enable' ) {
+                            $enabled = true;
+                        } elseif( $bapf_status == 'disable' ) {
+                            $enabled = false;
+                        }
+                    }
+                    do_action('brapf_next_shortcode_apply_action', array('apply' => $enabled));
+                } catch (Exception $err) {}
             }
             return $content;
         }

Exploit Outline

To exploit this vulnerability, an attacker must have Author-level permissions or higher on a site where both Advanced AJAX Product Filters and Live Composer are active. The attacker creates a new post or page and includes the shortcode [dslc_module_posts_output] followed by a malicious serialized PHP object and the closing shortcode tag. When the post is rendered (either via preview or by viewing the published post), the plugin's `shortcode_check` function processes the content of the shortcode through `unserialize()`, triggering the object injection. If a usable POP chain exists in any other active plugin or the theme, this can lead to remote code execution or other high-impact actions.

Check if your site is affected.

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