How BitFire Blocks CVE-2026-96039: BA Book Everything Stored XSS

WordPress vulnerability research

BitFire FREE Bot Protection and WAF stop CVE-2026-96039, an unauthenticated stored XSS chain in BA Book Everything, before the payload ever reaches WordPress.

Unauthenticated High severity (CVSS 7.2) Attacker script in site context Stored cross-site scripting
BitFire · Vulnerability advisoryResearch published
AdvisoryCVE-2026-96039
ComponentBA Book Everything
Relevant sourceincludes/class-babe-html.php — BABE_html::checkout_form() value attribute (sink); includes/class-babe-order.php — sanitize_checkout_vars() (input)
Executive summary

What WordPress administrators need to know

BA Book Everything, the WordPress booking plugin active on roughly 10,000 sites, exposed a stored cross-site scripting path through its guest checkout through version 1.8.27. An unauthenticated attacker creates a guest booking, receives the order credentials the checkout guards demand, then posts a crafted first_name that survives the plugin's weak sanitizer. The plugin later concatenates that value unescaped into the checkout form's value attribute, so anyone who opens that order's checkout URL runs attacker-controlled script in the site's context. BitFire FREE stops the attack at the request layer: Bot Protection blocks scripted form delivery before WordPress runs, and the WAF detects the payload before it is ever stored.

At a glance

Key facts

  • Unauthenticated reachability: guest bookings hand out the order_id, order_num, and order_hash required to reach action_to_pay()
  • sanitize_text_field() strips tags but preserves double quotes, letting first_name break out of the checkout form's value attribute
  • BABE_html::checkout_form() echoed the stored value without esc_attr(); any visitor loading the order's checkout URL executes attacker script
  • Fixed in 1.8.28: input runs through BABE_Functions::clear_string_from_special_chars() and output is escaped with esc_attr()
  • BitFire FREE Bot Protection blocks scripted form submissions before vulnerable WordPress code runs
  • BitFire FREE WAF detects the cross-site scripting payload in the checkout POST before it is stored
01
Vulnerability overview

Understand the exposure

The affected component, attack path, and practical risk for WordPress websites.

Affected componentBA Book Everything
Potential reach10000 installations
Attack techniquestored cross-site scripting
Published2026-09-27
BitFire stops CVE-2026-96039 twice: Bot Protection blocks scripted form submissions before WordPress runs, and the WAF detects the XSS payload in the checkout POST before it is ever stored.
02
Technical analysis

How the vulnerability works

Research details, affected versions, exploitation behavior, and remediation guidance.

CVE-2026-96039: How the Unauthenticated XSS Chain Works

BA Book Everything's booking and checkout handlers both hook template_redirect and consume $_POST directly on any front-end request, with no nonce and no capability check in the vulnerable tree. Reaching action_to_pay() only requires a valid order_id, order_num, and order_hash — and action_to_checkout() hands exactly those values to guests who submit the public booking form, by default without any account. The failure is two-sided: sanitize_checkout_vars() passes first_name through sanitize_text_field(), which strips tags but preserves double quotes, and BABE_html::checkout_form() concatenates the stored value raw into value="$field_content" on the checkout page. One quote breaks the attribute; the injected script then executes for every visitor who loads that order's checkout URL, including a logged-in administrator.

BitFire FREE Stops Delivery and Payload in One Pass

This chain is form-driven from start to finish, and BitFire Bot Protection is built for exactly that traffic. Scripted clients must pass lightweight browser verification before they can submit forms or POST data; scripts and fake browsers typically fail, so the booking and checkout submissions never reach vulnerable WordPress code. If a payload is submitted through inspected traffic anyway, the BitFire WAF inspects POST form data before WordPress processes it, detects the injected cross-site scripting payload, and blocks the request — nothing malicious reaches update_post_meta() or the checkout page. Both layers ship in BitFire FREE for eligible non-commercial websites; commercial sites need the appropriate commercial license. Bot checks stop automated delivery, not allowed clients — which is precisely why the WAF payload inspection stands behind them.

Update to BA Book Everything 1.8.28

Version 1.8.28 closes both ends of the chain. sanitize_checkout_vars() now runs first_name, last_name, and related checkout fields through the new BABE_Functions::clear_string_from_special_chars(), which deletes quotes, angle brackets, slashes, and other attribute-breaking characters before storage; sanitize_phone() bounds phone values. At the sink, checkout_form() wraps the field name, id, and value in esc_attr(), so even values stored under 1.8.27 cannot escape the attribute when rendered. Update immediately — the changelog confirms 1.8.28 is the security-fix release reported by Wordfence.

If Your Site Was Affected, Investigate for Persistence

Patching closes the documented path; it does not undo a compromise that already happened. If your site ran 1.8.27 or earlier, assume an attacker may have already planted a payload and had an administrator open it. Run BitFire Threat Hunter for a thorough post-compromise investigation: it discovers backdoor WordPress administrator accounts, hidden database triggers, long-running PHP processes, and droppers that restore malware or reinfect the site. Remove every persistence mechanism it finds and rotate administrator passwords and application passwords. Do not treat the absence of an obvious malicious file as proof your site is clean.

Protect the Checkout, Then Prove It Is Clean

Update BA Book Everything to 1.8.28 today. Keep BitFire in front of your checkout while you do: Bot Protection stops automated form delivery before WordPress runs, and the WAF detects XSS payloads in the POST before they are stored. If your site ran an affected version, finish the job with BitFire Threat Hunter to find and remove any persistence an attacker left behind. Deploy BitFire now and close this attack chain for good.

03
Source review

Vulnerable and fixed code

The relevant source is located in includes/class-babe-html.php — BABE_html::checkout_form() value attribute (sink); includes/class-babe-order.php — sanitize_checkout_vars() (input).

BeforeVulnerable behavior
// includes/class-babe-order.php — sanitize_checkout_vars() (vulnerable 1.8.27)
$output['first_name'] = isset($arr['first_name']) ? sanitize_text_field($arr['first_name']) : '';
$output['last_name'] = isset($arr['last_name']) ? sanitize_text_field($arr['last_name']) : '';

// includes/class-babe-html.php — BABE_html::checkout_form() sink (vulnerable 1.8.27)
<input type="text" class="checkout_input_field checkout_input_required" name="'.$field_name.'" id="'.$field_name.'" value="'.$field_content.'" '.apply_filters('babe_checkout_field_required', '', $field_name).'/>
AfterCorrected behavior
// includes/class-babe-order.php — sanitize_checkout_vars() (fixed 1.8.28)
$output['first_name'] = isset($arr['first_name'])
    ? BABE_Functions::clear_string_from_special_chars( sanitize_text_field($arr['first_name']) ) : '';
$output['last_name'] = isset($arr['last_name'])
    ? BABE_Functions::clear_string_from_special_chars( sanitize_text_field($arr['last_name']) ) : '';

// includes/class-babe-html.php — BABE_html::checkout_form() sink (fixed 1.8.28)
<input type="text" class="checkout_input_field checkout_input_required" name="'.esc_attr($field_name).'" id="'.esc_attr($field_name).'" value="'.esc_attr($field_content).'" '.apply_filters('babe_checkout_field_required', '', $field_name).'/>
04
Zero-day protection

Protection from the first exploit request

BitFire protects WordPress servers on day zero—before a vulnerability is publicly known and before other vendors have time to develop signatures or patches.

01 · VerifyStop unknown clients

Bot controls and browser verification stop untrusted automated clients before previously unknown exploit code reaches WordPress.

02 · DetectBlock malicious behavior

General WAF protections identify dangerous request behavior and hostile payloads without waiting for a vulnerability-specific signature.

03 · PreventContain attacks at runtime

RASP follows execution inside PHP and prevents unauthorized changes to protected files, accounts, and database content.

BitFire · WordPress protectionZero-day ready
BitFire combines verified-client controls, behavior-based WAF detection, and runtime RASP enforcement to protect WordPress before an exploit has a name, CVE, signature, or vendor patch.
About the author

Cory Marsh

Cory has more than 20 years of internet security experience and is a lead developer on the BitFire project.

Read BitFire security research →
Protect your WordPress website

Add protection before the next exploit arrives.

BitFire combines bot controls, request inspection, malware detection, and runtime protection in one WordPress security platform.

Protect my site free →