CVE-2026-92799 vulnerability and BitFire protection

How BitFire Blocks CVE-2026-92799: Bookly Type Juggling…

WordPress vulnerability research

BitFire FREE Bot Protection and BitFire PRO RASP stop the unauthenticated CVE-2026-92799 Bookly verification bypass that overwrites customer records.

Unauthenticated Medium CVSS 5.3 Customer record tampering Type juggling verification bypass
BitFire · Vulnerability advisoryResearch published
AdvisoryCVE-2026-92799
ComponentOnline Scheduling and Appointment Booking System – Bookly
Relevant sourcelib/Validator.php (postValidateCustomer); lib/UserBookingData.php (save)
Executive summary

What WordPress administrators need to know

Bookly, the appointment booking plugin installed on 60,000+ WordPress sites, trusted a loose PHP comparison to prove that a visitor owns a customer record. In 28.2, an unauthenticated request to admin-ajax.php could submit a type-juggled verification code, pass the ownership check without knowing the one-time code, and overwrite another customer's name, email, phone, birthday, and address — silently redirecting that customer's booking notifications to attacker-controlled contacts. BitFire FREE Bot Protection classifies and blocks the automated AJAX delivery, and BitFire PRO RASP halts the unauthorized database write to another person's record. Version 28.3 fixes the flawed comparison.

At a glance

Key facts

  • Delivered to /wp-admin/admin-ajax.php with no account, no nonce, and no knowledge of the victim's one-time code.
  • Root cause: loose '!=' and '==' comparisons in lib/Validator.php let a JSON non-string value match the session's non-zero six-digit code.
  • Sink: UserBookingData::save() overwrites name, email, phone, birthday, and address on the customer record matched by the attacker-chosen phone or email.
  • Impact is integrity-only (CVSS 5.3, C:N/I:L/A:N) — redirected booking notifications, no code execution or data exposure.
  • Bookly 28.3 compares codes with hash_equals(), binds the code to its original recipient, and gates record rewrites behind customerIdentityConfirmed().
  • BitFire FREE Bot Protection blocks automated delivery; BitFire PRO RASP blocks the unauthorized customer-record database write.
01
Vulnerability overview

Understand the exposure

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

Affected componentOnline Scheduling and Appointment Booking System – Bookly
Potential reach60000 installations
Attack techniquetype juggling authorization bypass
Published2026-09-27
BitFire FREE Bot Protection stops the automated AJAX delivery before WordPress runs, and BitFire PRO RASP refuses the unauthorized customer-record write — CVE-2026-92799 fails twice.
02
Technical analysis

How the vulnerability works

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

How CVE-2026-92799 Overwrites Bookly Customer Records

Bookly exposes its booking wizard through admin-ajax.php actions that require no login and no nonce: the controller registers bookly_session_save and bookly_save_appointment as wp_ajax_nopriv_ handlers and overrides csrfTokenValid() to return true. Its ownership check should stop a stranger from changing an existing customer record. In 28.2 that check compares the submitted verification_code against the six-digit code stored in the attacker's own session using a loose '!='. The json_data channel json_decode()s input and wp_kses() filters only strings, so a non-string JSON value passes through and PHP evaluates it as equal to any non-zero code. The gate never fires. saveAppointment() loads the victim's record via Customer::loadBy() on the attacker-chosen phone or email, and UserBookingData::save() overwrites its name, email, phone, birthday, and address.

BitFire FREE Bot Protection Stops the Automated Delivery

The entire attack is automated: scripted requests to /wp-admin/admin-ajax.php with the bookly_session_save and bookly_save_appointment actions, no login, no nonce. That is exactly the traffic BitFire FREE Bot Protection stops. Before WordPress or Bookly runs any code, Bot Protection classifies the request: unknown or restricted automation is limited to safe viewing and cannot call sensitive AJAX endpoints, submit forms, or POST exploit data, and clients presenting as browsers must pass lightweight JavaScript verification that real browsers normally pass automatically and scripted exploit clients fail. Known tools such as WPScan and nikto are blocked outright. A bot that cannot reach bookly_save_appointment never reaches the flawed comparison, and the customer record is never touched. This request-layer protection ships with BitFire FREE for eligible non-commercial sites; commercial sites need the matching commercial license.

BitFire PRO RASP Blocks the Unauthorized Database Write

If any request slips past the request layer — including a manually driven browser — BitFire PRO RASP enforces authorization at the protected operation itself. UserBookingData::save() is not WordPress core and not an approved membership or commerce plugin, so RASP treats its write of another person's bookly_customers row as exactly what it is: a non-admin account-record change with no legitimate authority behind it. The database protection guard blocks the unauthorized update before it persists, and the attacker's chosen name, email, phone, birthday, and address never reach the victim's record. RASP does not sanitize input and does not need to recognize CVE-2026-92799; it simply refuses the dangerous runtime outcome.

Patch to Bookly 28.3 and Verify Your Version

Update Bookly to 28.3 or later immediately. The fix replaces both loose comparisons with verificationCodeMatches(), which casts integers to strings, rejects any non-string submitted value, requires a digit-only code, and compares with hash_equals(). Version 28.3 also binds acceptance to the recipient the code was actually sent to, invalidates the stored code after five wrong entries, and gates record rewrites behind customerIdentityConfirmed() in UserBookingData::save(), so a matched record's filled fields are overwritten only when the session proves ownership. Admins should verify the installed version in main.php — 28.2 or lower is vulnerable. The endpoint itself remains nopriv-registered and CSRF-unchecked in 28.3, which is precisely why layered controls like Bot Protection and RASP matter even on patched sites.

If Your Site Was Affected, Investigate for Persistence

Patching closes the verification bypass; it does not undo an overwrite that already happened. If your site ran Bookly 28.2 or earlier, assume the exposure was live and investigate. Look for customer records whose contact details changed without a matching booking, check Bookly's notification routing, and rotate credentials for any account whose recovery email or phone points at attacker-controlled addresses. Run BitFire Threat Hunter for a thorough post-compromise sweep: it hunts backdoor WordPress administrator accounts, hidden database triggers, long-running PHP processes, and droppers that can restore malware or reinfect the site. This CVE does not grant code execution, but a site scanned by the same automation often carries other persistence. Remove what Threat Hunter finds and rotate the relevant credentials.

Stop the Next Exploit with BitFire

CVE-2026-92799 shows how one loose comparison turns a routine booking form into a customer-data tampering tool. BitFire stops this attack twice: BitFire FREE Bot Protection rejects the automated AJAX delivery before WordPress executes a single line of Bookly code, and BitFire PRO RASP blocks the unauthorized customer-record write at the database itself. Install Bookly 28.3 today, run Threat Hunter if 28.2 ever touched your site, and deploy BitFire to keep the next unauthenticated exploit from getting that far. Get BitFire FREE now and put layered protection in front of every request.

03
Source review

Vulnerable and fixed code

The relevant source is located in lib/Validator.php (postValidateCustomer); lib/UserBookingData.php (save).

BeforeVulnerable behavior
if ( $data['verification_code'] != $userData->getVerificationCode() ) {
    $this->errors['verify'] = $identifier;
}
AfterCorrected behavior
if ( self::verificationCodeMatches( $data['verification_code'], $userData->getVerificationCode() )
    && $recipient !== ''
    && $sent_recipient === $recipient
) {
    $userData->setVerifiedRecipient( $recipient );
    $userData->setVerificationAttemptCount( 0 );
} else {
    $this->registerVerificationAttempt( $data, $userData );
    $this->errors['verify'] = $identifier;
}
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 zero-day WordPress vulnerability protection
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 →