Automated Threat Modeling

Brief Summary: Amelia WordPress Plugin CVE-2026-5465 IDOR Privilege Escalation via externalId Parameter

A short review of CVE-2026-5465, an Insecure Direct Object Reference in the Amelia WordPress booking plugin that lets Employee-level users take over any account, including Administrator accounts. Includes patch analysis and affected version details.

CVE Analysis

8 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-04-06

Brief Summary: Amelia WordPress Plugin CVE-2026-5465 IDOR Privilege Escalation via externalId Parameter
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A missing authorization check on a single field in the Amelia WordPress booking plugin gives any Employee-level user a direct path to full Administrator account takeover. The plugin has over 90,000 active installations, and exploitation is trivial, with no special tooling required. WordPress administrators running multi-provider booking setups should address CVE-2026-5465 without delay.

The Booking for Appointments and Events Calendar, known as Amelia, is a popular WordPress plugin that handles appointment scheduling, event booking, and calendar management for service-based businesses. Its users span a broad range of industries, including salons, clinics, and consulting firms. The role-based access model includes Provider (Employee) accounts, which are often assigned to staff or contractors who manage their own schedules through the WordPress backend.

Technical information

Root cause: authorization bypass via user-controlled key (CWE-639)

The vulnerability is in the UpdateProviderCommandHandler class, in the way it processes profile update requests from Provider (Employee) users. The handler merges every user-submitted field into the updated user object with array_merge($oldUser->toArray(), $providerData) and never restricts which fields a non-admin user may modify.

One of the merged fields is externalId, which maps directly to a WordPress user ID. It is used for more than display. The handler later passes it to two critical WordPress core functions:

  1. wp_set_password() at line 219, which sets the password for the WordPress user identified by externalId.
  2. wp_update_user() at line 239, which updates the profile details (email, name, etc.) of the WordPress user identified by externalId.

No server-side check stops a non-admin user from changing their externalId to an arbitrary value, so the entire chain, from field submission to execution of privileged WordPress functions, is unguarded.

Attack flow

The exploitation path is straightforward:

  1. The attacker authenticates to WordPress with a Provider (Employee) account. This is the minimum privilege level required.
  2. The attacker starts a profile update request through the Amelia plugin interface. The request hits the UpdateProviderController at line 30, which delegates to the UpdateProviderCommandHandler.
  3. The attacker intercepts the outgoing HTTP request (with a proxy or browser developer tools) and changes the externalId parameter in the request body to the WordPress user ID of the target account. For example, user ID 1 is typically the site's original Administrator.
  4. The attacker also puts their chosen new password in the request payload.
  5. The UpdateProviderCommandHandler merges the submitted data with the existing provider record via array_merge() and accepts the attacker-supplied externalId without question.
  6. The handler calls wp_set_password() with the attacker's password and the injected externalId (the Administrator's WordPress user ID), which resets the Administrator's password.
  7. The handler calls wp_update_user() with the injected externalId, which may also overwrite the Administrator's email and other profile fields.
  8. The attacker logs in as the Administrator with the new password.

CVSS 3.1 breakdown

MetricValueImplication
Attack VectorNetworkExploitable remotely over the internet
Attack ComplexityLowNo advanced techniques or race conditions required
Privileges RequiredLowRequires only basic Employee or Provider access
User InteractionNoneNo victim action needed
Confidentiality ImpactHighFull access to all site data
Integrity ImpactHighComplete control over site content and configuration
Availability ImpactHighAttacker can lock out legitimate administrators

The overall score of 8.8 (High) is accurate for a flaw with a low barrier to entry that ends in total site compromise when the attack succeeds.

Patch information

The vendor fixed CVE-2026-5465 in version 2.2 of the Amelia plugin. The fix is tracked in the WordPress plugin repository under changeset 3499608.

The patch adds a targeted authorization guard right after the UserFactory::create($newUserData) call, which builds the new user entity from the merged data:

$oldExternalId = $oldUser->getExternalId() ? $oldUser->getExternalId()->getValue() : null; $newExternalId = $newUser->getExternalId() ? $newUser->getExternalId()->getValue() : null; if ($oldExternalId !== $newExternalId && (!$currentUser || $currentUser->getType() !== AbstractUser::USER_ROLE_ADMIN)) { $result->setResult(CommandResult::RESULT_ERROR); $result->setMessage('Could not update user.'); return $result; }

The guard compares the externalId already stored on the existing provider record ($oldExternalId) with the externalId in the incoming update request ($newExternalId). A mismatch means someone tried to change which WordPress user the provider is linked to. If that happens and the logged-in user is not an Administrator, the handler returns an error and stops, so a tampered externalId never reaches the downstream wp_set_password() or wp_update_user() calls.

The check sits after all field merging has happened but before any privileged WordPress operation runs, which makes it a final gate. With the patch, only Administrators can reassign the externalId mapping, and that is the correct authorization model. Employees should never be able to re-link their Amelia provider profile to a different WordPress account.

To apply the fix, update to Amelia version 2.2 or later through the standard WordPress plugin update mechanism. After updating, confirm in the WordPress plugin dashboard that the active version shows 2.2. You can review the patched source in the version 2.2 tag.

Affected systems and versions

Every version of the Booking for Appointments and Events Calendar, Amelia plugin for WordPress, from the initial release through version 2.1.3 (inclusive), is vulnerable. Version 2.2 contains the fix.

Organizations should patch first wherever third-party users, contractors, or lower-privileged staff hold Provider or Employee roles in Amelia. Those accounts have exactly the access the exploit requires.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization