[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f49RtBfa3izG_DJg0BQbXrgF5q4DxgXVQtNtJ2ge-V_A":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-59521","real-testimonials-testimonial-slider-collect-customer-reviews-and-video-testimonials-authenticated-administrator-php-obj","Real Testimonials – Testimonial Slider, Collect Customer Reviews and Video Testimonials \u003C= 3.1.15 - Authenticated (Administrator+) PHP Object Injection","The Real Testimonials – Testimonial Slider, Collect Customer Reviews and Video Testimonials plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 3.1.15 via deserialization of untrusted input. This makes it possible for authenticated attackers, with administrator-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.","testimonial-free",null,"\u003C=3.1.15","3.1.16","medium",6.6,"CVSS:3.1\u002FAV:N\u002FAC:H\u002FPR:H\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Deserialization of Untrusted Data","2026-07-07 00:00:00","2026-07-14 19:50:52",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F0d423c90-89ca-4295-92eb-d26acd445db0?source=api-prod",8,[22,23,24,25,26,27,28,29],"readme.txt","src\u002FAdmin\u002FHelpPage\u002FHelp.php","src\u002FAdmin\u002FViews\u002FFramework\u002FClasses\u002Fmetabox.class.php","src\u002FAdmin\u002FViews\u002FFramework\u002FClasses\u002Foptions.class.php","src\u002FAdmin\u002FViews\u002FFramework\u002Fconfigs\u002Ftools.php","src\u002FAdmin\u002FViews\u002FNotices\u002FShapedPlugin_Offer_Banner.php","src\u002FAdmin\u002FViews\u002FNotices\u002FTestimonial_Review.php","src\u002FFrontend\u002FViews\u002Fpartials\u002Fsubmit-form.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-59521\n\n## 1. Vulnerability Summary\nThe **Real Testimonials** plugin (versions \u003C= 3.1.15) is vulnerable to **PHP Object Injection** via the deserialization of untrusted input. The vulnerability typically resides in the \"Tools\" or \"Settings\" import functionality, where the plugin uses the `SPFTESTIMONIAL` (Codestar-like) framework to handle configuration imports. By providing a crafted serialized string—often Base64 encoded—to the import field, an authenticated administrator can trigger the `unserialize()` sink. While no POP chain is identified in the plugin itself, any chain present in the WordPress environment (other plugins\u002Fthemes) can be leveraged for RCE or file manipulation.\n\n## 2. Attack Vector Analysis\n*   **Target Endpoint**: `\u002Fwp-admin\u002Fedit.php?post_type=spt_testimonial&page=testimonial_tools`\n*   **Vulnerable Parameter**: The import data field, typically named after the framework prefix: `sp_testimonial_pro_tools[import]` or a similar key within the POST body.\n*   **Authentication**: Required (Administrator+).\n*   **Preconditions**: The attacker must have access to the \"Tools\" submenu under the \"Real Testimonials\" menu.\n\n## 3. Code Flow\n1.  **Registration**: The \"Tools\" page is registered in `src\u002FAdmin\u002FViews\u002FFramework\u002Fconfigs\u002Ftools.php` with the unique prefix `sp_testimonial_pro_tools`.\n2.  **Framework Initialization**: The `SPFTESTIMONIAL_Options` class (in `src\u002FAdmin\u002FViews\u002FFramework\u002FClasses\u002Foptions.class.php`) initializes the settings page for this prefix.\n3.  **Import Logic**: When the \"Import\" form is submitted, the framework processes the input. In the underlying framework (Codestar derivative), the `import` field type triggers a block of code that:\n    *   Retrieves the string from the POST request or uploaded file.\n    *   Decodes it (if Base64 encoded).\n    *   Passes it to `unserialize()` or `maybe_unserialize()` to restore the option array.\n4.  **Sink**: The `unserialize()` function is called on the attacker-controlled string, leading to object instantiation.\n\n## 4. Nonce Acquisition Strategy\nThe \"Tools\" page uses a nonce for form security.\n1.  **Identify Page**: The \"Tools\" page is located at `edit.php?post_type=spt_testimonial&page=testimonial_tools`.\n2.  **Locate Nonce**: The framework typically embeds a nonce in a hidden field named `_wpnonce` or similar, tied to the prefix `sp_testimonial_pro_tools`.\n3.  **Extraction**:\n    *   Navigate to the Tools page.\n    *   Use `browser_eval` to extract the nonce from the form.\n    *   Variable check: Look for `window.sp_testimonial_pro_tools_vars` or simply the hidden input field.\n\n```javascript\n\u002F\u002F Example extraction via browser_eval\ndocument.querySelector('input[name=\"_wpnonce\"]')?.value || \ndocument.querySelector('input[name=\"sp_testimonial_pro_tools_nonce\"]')?.value;\n```\n\n## 5. Exploitation Strategy\n### Step 1: Preparation\nConstruct a simple PHP Object Injection payload. Since no specific POP chain is required for the PoC, we use `stdClass`.\n*   **Payload**: `O:8:\"stdClass\":1:{s:3:\"foo\";s:3:\"bar\";}`\n*   **Encoding**: Base64 encode the payload if the framework expects it (likely): `Tzo4OiJzdGRDbGFzcyI6MTp7czozOiJmb28iO3M6MzoiYmFyIjt9`\n\n### Step 2: HTTP Request\nUse the `http_request` tool to send a POST request to the Tools page.\n\n*   **URL**: `https:\u002F\u002F\u003Ctarget>\u002Fwp-admin\u002Fedit.php?post_type=spt_testimonial&page=testimonial_tools`\n*   **Method**: `POST`\n*   **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Body**:\n    ```text\n    sp_testimonial_pro_tools%5Bimport%5D=Tzo4OiJzdGRDbGFzcyI6MTp7czozOiJmb28iO3M6MzoiYmFyIjt9&_wpnonce=\u003CNONCE>&sp_testimonial_pro_tools_import_button=1\n    ```\n    *(Note: Parameter names like `sp_testimonial_pro_tools_import_button` are inferred from standard framework behavior and should be verified via `browser_eval` on the page source.)*\n\n## 6. Test Data Setup\n1.  **Plugin Installation**: Ensure \"Real Testimonials\" \u003C= 3.1.15 is installed and activated.\n2.  **User**: An Administrator user is required for the session.\n3.  **Page Creation**: No specific frontend content is needed as the vulnerability is in the Admin backend.\n\n## 7. Expected Results\n*   The server processes the request.\n*   If a debugger like Xdebug is active or the object has a `__wakeup` method that triggers an error, the error will be visible.\n*   In a successful \"blind\" injection, the framework might attempt to replace existing options with the \"array\" it expected, potentially breaking plugin settings (a sign that the data was processed).\n\n## 8. Verification Steps\nSince this is a deserialization vulnerability without a confirmed POP chain in the plugin, verification involves confirming the sink is reached:\n1.  **Error Logs**: Check `wp-content\u002Fdebug.log` for \"Notice: unserialize(): Error at offset...\" if the payload is slightly malformed, confirming `unserialize` was called.\n2.  **Database Check**: If the injection was intended to overwrite options, use `wp option get sp_testimonial_pro_tools` to see if the data changed.\n3.  **Dummy Class**: Create a temporary file in the plugin directory containing a dummy class with a `__destruct` method that writes to a file, then try to inject that class.\n\n## 9. Alternative Approaches\n*   **File Upload**: The `tools.php` file defines the import as \"Import JSON\u002FCSV File\". If the POST parameter fails, try uploading a `.json` file containing the serialized string via a `multipart\u002Fform-data` request to the same endpoint.\n*   **Metabox Injection**: Check if the `save_meta_box` function in `src\u002FAdmin\u002FViews\u002FFramework\u002FClasses\u002Fmetabox.class.php` (Line 115) accepts serialized strings for fields with `'data_type' => 'serialize'`. If so, updating a Testimonial post via the REST API or Admin editor with a crafted meta value could trigger the vulnerability upon the next page load.","The Real Testimonials plugin for WordPress is vulnerable to PHP Object Injection in versions up to and including 3.1.15 due to the use of the unsafe `maybe_unserialize` function on user-supplied import data. Authenticated administrators can exploit this by submitting crafted serialized objects through the plugin's 'Tools' import feature, potentially leading to remote code execution or file manipulation if a suitable POP chain exists on the site.","\u002F\u002F src\u002FIncludes\u002FImport_Export.php:133\n$export['shortcode'][ $key ]['meta']['sp_tpro_meta_options'] =\nisset( $export['shortcode'][ $key ]['meta']['sp_tpro_meta_options'] )\n\t? maybe_unserialize( $export['shortcode'][ $key ]['meta']['sp_tpro_meta_options'] )\n\t: '';\n\n---\n\n\u002F\u002F src\u002FIncludes\u002FImport_Export.php:335\nif ( is_string( $value ) ) {\n\t$value = maybe_unserialize( str_replace( '{#ID#}', $new_shortcode_id, $value ) );\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ftestimonial-free\u002F3.1.15\u002Fsrc\u002FIncludes\u002FImport_Export.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ftestimonial-free\u002F3.1.16\u002Fsrc\u002FIncludes\u002FImport_Export.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ftestimonial-free\u002F3.1.15\u002Fsrc\u002FIncludes\u002FImport_Export.php\t2025-09-01 08:09:28.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ftestimonial-free\u002F3.1.16\u002Fsrc\u002FIncludes\u002FImport_Export.php\t2026-07-07 07:05:28.000000000 +0000\n@@ -130,7 +130,7 @@\n \t\t\tforeach ( $export['shortcode'] as $key => $value ) {\n \t\t\t\t$export['shortcode'][ $key ]['meta']['sp_tpro_meta_options'] =\n \t\t\t\tisset( $export['shortcode'][ $key ]['meta']['sp_tpro_meta_options'] )\n-\t\t\t\t\t? maybe_unserialize( $export['shortcode'][ $key ]['meta']['sp_tpro_meta_options'] )\n+\t\t\t\t\t? $this->maybe_unserialize( $export['shortcode'][ $key ]['meta']['sp_tpro_meta_options'] )\n \t\t\t\t\t: '';\n \t\t\t}\n \t\t}\n@@ -153,32 +153,20 @@\n \t\twp_send_json( $export, 200 );\n \t}\n \n-\n \t\u002F**\n-\t * Get page by title\n+\t * Maybe unserialize data if it is serialized.\n \t *\n-\t * @param string $page_title Page title.\n-\t * @param string $output Optional.\n-\t * @param string $post_type Post type.\n-\t * @return obj.\n+\t * @param  mixed $data Data to maybe unserialize.\n+\t * @param  mixed $options Options for unserialization.\n+\t * @return mixed\n \t *\u002F\n-\tpublic function sp_testimonial_get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {\n-\t\tglobal $wpdb;\n-\t\t$sql  = $wpdb->prepare(\n-\t\t\t\"\n-\t\t\tSELECT ID\n-\t\t\tFROM $wpdb->posts\n-\t\t\tWHERE post_title = %s\n-\t\t\tAND post_type = %s\n-\t\t\",\n-\t\t\t$page_title,\n-\t\t\t$post_type\n-\t\t);\n-\t\t$page = $wpdb->get_var( $sql ); \u002F\u002F phpcs:ignore -- WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching\n-\t\tif ( $page ) {\n-\t\t\treturn get_post( $page, $output );\n+\tpublic function maybe_unserialize( $data, $options = array() ) {\n+\t\tif ( is_serialized( $data ) ) {\n+\t\t\t$default_option = array( 'allowed_classes' => false );\n+\t\t\t$options        = wp_parse_args( $options, $default_option );\n+\t\t\treturn unserialize( $data, $options ); \u002F\u002F phpcs:ignore -- dissallowed any classes.\n \t\t}\n-\t\treturn null;\n+\t\treturn $data;\n \t}\n \n \t\u002F**\n@@ -332,7 +316,7 @@\n \t\t\t\tif ( isset( $shortcode['meta'] ) && is_array( $shortcode['meta'] ) ) {\n \t\t\t\t\tforeach ( $shortcode['meta'] as $key => $value ) {\n \t\t\t\t\t\tif ( is_string( $value ) ) {\n-\t\t\t\t\t\t\t$value = maybe_unserialize( str_replace( '{#ID#}', $new_shortcode_id, $value ) );\n+\t\t\t\t\t\t\t$value = $this->maybe_unserialize( str_replace( '{#ID#}', $new_shortcode_id, $value ) );\n \t\t\t\t\t\t}\n \t\t\t\t\t\tupdate_post_meta(\n \t\t\t\t\t\t\t$new_shortcode_id,","1. Authenticate as an Administrator and navigate to the 'Tools' page under the 'Real Testimonials' menu (`\u002Fwp-admin\u002Fedit.php?post_type=spt_testimonial&page=testimonial_tools`).\n2. Prepare a PHP Object Injection payload, such as a serialized object using `stdClass` or any valid POP chain present in the environment (e.g., `O:8:\"stdClass\":1:{s:3:\"foo\";s:3:\"bar\";}`).\n3. Base64 encode the serialized string if required by the framework's import handler.\n4. Extract the security nonce (`_wpnonce`) from the page's HTML form.\n5. Send a POST request to the Tools page including the crafted string in the `sp_testimonial_pro_tools[import]` parameter (or the relevant framework import field) and the valid nonce. This will trigger the `maybe_unserialize` sink in the `Import_Export.php` class during processing.","gemini-3-flash-preview","2026-07-25 09:05:26","2026-07-25 09:06:47",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","3.1.15","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftestimonial-free\u002Ftags\u002F3.1.15","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ftestimonial-free.3.1.15.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftestimonial-free\u002Ftags\u002F3.1.16","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ftestimonial-free.3.1.16.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftestimonial-free\u002Ftags"]