PoC Archive PoC Archive
High CVE-2026-40791 patched

WP Time Slots Booking Form Unauthenticated Stored XSS (CVE-2026-40791)

by Daniel Wade (Rat5ak / Nadsec) · 2026-07-05

CVSS 7.2/10
Severity
High
CVE
CVE-2026-40791
Category
web
Affected product
WP Time Slots Booking Form (wp-time-slots-booking-form WordPress plugin)
Affected versions
<= 1.2.46 (fixed in 1.2.47)
Disclosed
2026-07-05
Patch status
patched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-04
Author / ResearcherDaniel Wade (Rat5ak / Nadsec)
CVE / AdvisoryCVE-2026-40791
Categoryweb
SeverityHigh
CVSS Score7.2 (Wordfence), 7.1 (Patchstack)
StatusPoC
Tagswordpress, wordpress-plugin, stored-xss, unauthenticated, cwe-79, admin-takeover, booking-form
RelatedN/A

Affected Target

FieldValue
Software / SystemWP Time Slots Booking Form (wp-time-slots-booking-form WordPress plugin)
Versions Affected<= 1.2.46 (fixed in 1.2.47)
Language / PlatformPHP / WordPress; PoC in Bash and PowerShell
Authentication RequiredNo (unauthenticated submitter); admin only needs to view a page
Network Access RequiredYes

Summary

The public booking form of the WP Time Slots Booking Form plugin parses a submitted appointment field by splitting on a literal space character, then stores the resulting substring as the booking’s time-slot value. Because HTML treats a tab character as valid whitespace between an SVG tag and its attribute, an attacker can submit a payload like 8:<svg[TAB]onload=alert(document.cookie)> — PHP’s explode(' ', ...) keeps it as a single token (since it only splits on spaces, not tabs), but the browser still parses it as a real <svg onload=...> element. That value is serialized and later printed, unescaped, into the administrator’s Booking Orders page (a phpcs:ignore WordPress.Security.EscapeOutput comment marks the exact line where escaping was suppressed). When an administrator views Booking Orders, the attacker’s JavaScript executes in the authenticated wp-admin origin.


Vulnerability Details

Root Cause

extract_appointments() splits the submitted appointment string with explode(' ', $app_item_text) and stores $item_split[1] as the slot value without validation; the admin-facing renderer in cp-admin-int-message-list.inc.php then concatenates that stored value directly into HTML output with escaping explicitly suppressed via a phpcs:ignore comment.

Attack Vector

  1. Submit an unauthenticated POST to the plugin’s public booking form endpoint with the appointment field crafted as 2026-04-15 8:<svg[TAB]onload=alert(document.cookie)> 1 0 0 0 0 0 0 (tab character between svg and onload).
  2. The plugin’s space-based parser preserves the tab-separated SVG tag intact as the stored “slot” value and serializes it into wp_cptslotsbk_messages.posted_data.
  3. An administrator opens the plugin’s Booking Orders admin page, which unserializes and prints the stored slot value without HTML-escaping it.
  4. The embedded <svg onload=...> executes in the administrator’s browser, in the wp-admin origin.

Impact

Unauthenticated stored XSS that executes in an administrator’s authenticated wp-admin session; while HttpOnly may protect the raw auth cookie, the script can still make same-origin authenticated requests (reading nonces, submitting admin POSTs), enabling site takeover actions such as creating users or changing plugin/site configuration.


Environment / Lab Setup

Target:   WordPress + WP Time Slots Booking Form <= 1.2.46, public booking page (e.g. page_id with [CP_TIME_SLOTS_BOOKING id="1"])
Attacker: bash+curl or PowerShell (see poc/reproduce.sh, poc/reproduce.ps1); admin browser to observe execution

Proof of Concept

PoC Script

See poc/reproduce.sh, poc/reproduce.ps1, and lab/render-check.html / lab/validate-render.ps1 in this folder.

1
2
./poc/reproduce.sh "http://127.0.0.1" 2
.\poc\reproduce.ps1 -Target "http://127.0.0.1" -PageId 2

The script submits an unauthenticated booking to the target’s public booking form with the tab-separated SVG payload embedded in the appointment field, expecting an HTTP 302 response confirming acceptance. lab/validate-render.ps1 independently verifies the two mechanical parts of the bug (that the PHP-style space-split preserves the tabbed SVG, and that a browser executes the resulting markup) without requiring a full WordPress install.


Detection & Indicators of Compromise

Signs of compromise:

  • Stored booking rows in wp_cptslotsbk_messages containing HTML tags in the slot/time field
  • Unexpected admin session activity (new users, changed settings) shortly after an admin viewed Booking Orders
  • <svg onload=...> or similar markup appearing in booking-related database entries

Remediation

ActionDetail
Primary fixUpdate WP Time Slots Booking Form to 1.2.47 or later, which applies esc_html() to the stored slot value before rendering
Interim mitigationDisable the plugin’s public booking form or restrict admin access to Booking Orders until patched; a WAF rule blocking tab characters adjacent to < in form submissions can reduce exposure

References


Notes

Mirrored from https://github.com/Rat5ak/CVE-2026-40791-WP-Time-Slots-Booking-Form-XSS on 2026-07-05.