Advanced AJAX Product Filters <= 3.1.9.6 - Authenticated (Author+) PHP Object Injection via Live Composer Compatibility
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:HTechnical Details
<=3.1.9.6What Changed in the Fix
Changes introduced in v3.1.9.7
Source Code
WordPress.org SVN# 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_tagfilter hook. - Hook Registration:
add_filter('pre_do_shortcode_tag', array($this, 'shortcode_check'), 10, 5);inincludes/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
- Entry Point: A user with Author+ permissions saves or previews a post containing the shortcode:
[dslc_module_posts_output]{PAYLOAD}[/dslc_module_posts_output]. - Filter Execution: When WordPress renders the post,
do_shortcode()calls thepre_do_shortcode_tagfilter. - Vulnerable Function:
BeRocket_AAPF_compat_live_composer_builder::shortcode_check($content, $tag, $attr, $m)is executed. - Tag Verification: The function checks if
$tag == 'dslc_module_posts_output'. - Extraction: The variable
$argsis populated from$m[5], which represents the inner content of the shortcode. - 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.
- Capability: Authenticated as Author.
- Method: Use the WordPress REST API to create a post.
- Nonce Requirement: The REST API requires a
_wpnoncein theX-WP-Nonceheader. - 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
_wpnonceand_wp_http_refererfrom thepost-new.phppage).
- Navigate to
5. Exploitation Strategy
Step 1: Pre-requisite Setup
- Ensure "Live Composer" (slug:
live-composer-page-builder) is active. - 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/jsonX-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 executesunserialize()on thestdClassobject.
6. Test Data Setup
- User: Create a user with the Author role.
wp user create attacker attacker@example.com --role=author --user_pass=password
- 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__wakeupor__destructmethod would have fired if a POP chain existed. - The
shortcode_checkfunction 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
- Check Post Content:
wp post get [POST_ID] --field=content- Confirm the shortcode and payload are stored exactly as sent.
- Monitor Logs:
- Monitor
wp-content/debug.logwhile visiting the post. - Look for
unserialize()related errors or class instantiation attempts if using a custom payload.
- Monitor
9. Alternative Approaches
If the REST API is disabled:
- Navigate to
wp-admin/post-new.php. - Extract the
_wpnoncefrom the form usingbrowser_eval("jQuery('#_wpnonce').val()"). - Submit a standard
multipart/form-dataPOST request towp-admin/post.phpto save the post. - Proceed to Step 4 of the Exploitation Strategy.
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
@@ -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.