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.