Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-18366 — Unauthenticated privilege-escalation PoC for WordPress Events Manager < 7.4.1; discovers colliding post/user IDs and escalates targets to administrator via REST or wp-admin. | Kitploit
Tools/GitHubGitHub/ghostpels/cve-2026-18366
Privilege EscalationVulnerability AnalysisExploitationWeb Application ExploitationInformation Gathering
GitHubghostpels/cve-2026-18366

CVE-2026-18366

Unauthenticated privilege-escalation PoC for WordPress Events Manager < 7.4.1; discovers colliding post/user IDs and escalates targets to administrator via REST or wp-admin.

View Repository
591 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-18366 — Events Manager < 7.4.1: Unauthenticated Privilege Escalation to Administrator

ProductEvents Manager (WordPress plugin)
Affected versions7.1.0 – 7.4.0.x
Fixed version7.4.1
WeaknessCWE-269: Improper Privilege Management
SeverityCVSS 3.1: 9.8 (Critical) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
WPVDB ID82767ce2-01e4-46ad-a52b-72d3ab2049bd
Original researcherJakub Herman
Write-up & PoCghostpel

Disclosure timeline

  • 2026-08-03 — Events Manager 7.4.1 released with the fix (vendor security release).
  • 2026-08-12 — IONIX Threat Center entry published.
  • 2026-08-21 — This write-up and proof-of-concept (poc.py).

Summary

Events Manager versions 7.1.0 through 7.4.0.x contain a privilege escalation vulnerability that allows a completely unauthenticated attacker to take over any user account whose ID collides with the ID of one of the plugin's own posts (event / location / event-recurring / location-recurring). The collision can be forced on sites with guest bookings enabled (the default): every guest booking creates a real user account and advances the wp_users auto-increment counter by one, letting an attacker "walk" the user ID space onto an event/location post ID.

The root cause: the plugin's map_meta_cap filter discards the capability list WordPress already computed ($caps = []) for any meta capability, whenever the capability's object ID happens to resolve to an event/location post — including WordPress core capabilities such as edit_user, delete_user, promote_user, and remove_user. An empty capability list reads as "no capability required" — i.e. allow for everyone, including logged-out users.

Consequences (all unauthenticated, via the WP REST API): change any colliding account's password, escalate it to administrator, or delete it.

Version analyzed: 7.4.0.1 (vulnerable) — diffed against 7.4.1 (fixed).

Affected versions

VersionStatus
≤ 7.0.5Not affected (legacy em_map_meta_cap only handles EM's own capabilities)
7.1.0 – 7.4.0.xVulnerable (the archetype system with the buggy map_meta_cap was introduced in 7.1.0)
7.4.1Fixed

Root cause — map_meta_cap empties $caps

classes/em-archetypes.php (version 7.4.0.1):

LineCodeRole
:33add_filter( 'map_meta_cap', [ static::class, 'map_meta_cap'], 10, 4 );Global, unconditional filter — runs for every WordPress meta-capability check, including core's and those for logged-out users
:547if ( !empty( $args[0] ) ) {The capability's object is taken as a post ID
:548$post = get_post($args[0]);ID collision: the target user ID (for caps like edit_user) is treated as a post ID
:551`if( empty($post->post_type)
:563`if ( !empty( $c['read'][$post->post_type] )
:564–565$caps = [];The capability list is discarded unconditionally — even though the requested cap is not a read/edit/delete_event archetype cap
:568/577/584if/elseif branches$caps is only refilled when $cap exactly matches an archetype meta cap; for edit_user, delete_user, promote_user, remove_user no branch matches → $caps stays empty
:597return $caps;Empty array = "no capability required" = ALLOW for anyone, including user ID 0

Consequence: every current_user_can('edit_user', X) / delete_user / promote_user / remove_user check returns TRUE whenever X equals the ID of an event/location post. The plugin "discards the access control decisions WordPress had already made" — exactly as described by WPScan.

The fix in 7.4.1

Verified by diffing 7.4.0.1 against 7.4.1: the reset is now guarded by an exact capability match per branch (e.g. && $c['read'][$post->post_type] == $cap), so $caps is only emptied when the requested capability really is an archetype meta cap. Patch comment: "Resetting on any object-carrying cap emptied the requirement list for unrelated caps (e.g. edit_user, promote_user), which reads as allow."

Impact — exposed WordPress core admin operations (no login, via REST API)

The REST Users endpoints (/wp-json/wp/v2/users/{id}) have no global login gate — access control is purely via permission callbacks, all of which flow through the same map_meta_cap filter:

ActionEndpoint / core functionBypassed capability
Change the target account's passwordPUT /wp-json/wp/v2/users/{id} with {"password":"..."} → wp_update_user() (internal edit_user check)edit_user
Escalate the account to AdministratorPUT /wp-json/wp/v2/users/{id} with {"roles":["administrator"]}promote_user
Delete an accountDELETE /wp-json/wp/v2/users/{id}?reassign=... → wp_delete_user() (internal delete_user check)delete_user
(Multisite) remove a user from the blogremove_userremove_user

Side effect: edit_comment is also affected when a comment ID happens to equal an event/location post ID (the wp_comments table shares the numeric space).

Forcing the ID collision via guest booking (entry point)

The collision exists because wp_users.ID and wp_posts.ID are independent auto-increment sequences that inevitably overlap. Guest bookings force it:

  • em-install.php:896 — dbem_bookings_anonymous = 1: guest bookings enabled by default; :871 dbem_bookings_registration_disable = 0 (registration enabled).
  • em-actions.php:340-344 — booking_add is in $booking_nopriv_actions → callable without login (via wp_ajax_nopriv_booking_add, priority 999999, lines :817-830, or wp_loaded :11).
  • em-actions.php:360-375 — booking_add flow: em_verify_nonce('booking_add') → get_post() → validate() → em_booking_add_registration() → $EM_Bookings->add(). (The nonce is CSRF protection only — the booking_add nonce is rendered on the public booking form, so anyone can obtain it.)
  • em-functions.php:405-417 — guest branch: em_register_new_user($user_data) with the attacker's email.
  • em-functions.php:510 — wp_insert_user($user_data) → wp_users auto-increment advances by 1 per guest booking → the attacker controls the growth rate of the user ID counter until it lands on the desired event/location post ID (WPScan: "each guest booking creates a real user account and advances the user ID counter by one").

Secondary chain observed during the audit (booking attribution via person_id) — events-manager.php:430-437 (em_load_event, $EM_Person from $_REQUEST['person_id'] without login), em-booking.php:1060-1072 (get_person() overrides the person_id of a new booking), em-booking.php:2004-2006 (can_manage() = TRUE for a booking without ID), em-functions.php:448-449 — unchanged in 7.4.1; it is a separate vector (booking mis-attribution), not the core of this CVE.

Exploitation (unauthenticated)

Download Tool