ZeroPath at Black Hat USA 2026

Events Calendar for GeoDirectory CVE-2026-11616: Subscriber to Admin Privilege Escalation via User Meta Injection

A brief summary of CVE-2026-11616, a privilege escalation vulnerability in the Events Calendar for GeoDirectory WordPress plugin that allows Subscriber accounts to gain Administrator access through unchecked user meta key writes. Includes patch analysis and mitigation guidance.

CVE Analysis

10 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-06-09

Events Calendar for GeoDirectory CVE-2026-11616: Subscriber to Admin Privilege Escalation via User Meta Injection
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 single crafted POST request from a WordPress Subscriber account is all it takes to gain full Administrator access on any site running the Events Calendar for GeoDirectory plugin version 2.3.28 or earlier. The vulnerability, tracked as CVE-2026-11616 with a CVSS 3.1 score of 8.8, stems from the plugin's RSVP handler accepting arbitrary user meta keys without validation, allowing an attacker to inject the administrator role directly into their own wp_capabilities row.

The Events Calendar for GeoDirectory is an add-on plugin developed by AyeCode Ltd that extends their flagship GeoDirectory business directory plugin with event listing, scheduling, and RSVP functionality. The add-on has 2,000+ active installs, while the parent GeoDirectory core plugin runs on 10,000+ sites, and AyeCode's products collectively serve over 125,000 websites. Sites using this plugin typically operate community directories, local business listings, and event calendars, making them attractive targets for attackers seeking to compromise WordPress installations with active user bases.

Technical Information

Root Cause: Sanitization Without Semantic Validation

The vulnerability lives in class-geodir-event-ayi.php, specifically in the ajax_ayi_action() AJAX handler (line 154) and the update_ayi_data() function (line 357). The core problem is a fundamental confusion between sanitization and validation. The handler applies strip_tags(esc_sql()) to user input, which prevents HTML injection and SQL injection, but does nothing to restrict which meta keys can be written. A string like wp_capabilities contains no HTML tags and no SQL metacharacters, so it passes through both functions completely untouched.

In the vulnerable version (2.3.28), the AJAX handler processes POST parameters like this:

// Vulnerable code in v2.3.28: $action = strip_tags(esc_sql($_POST['btnaction'])); $type = strip_tags(esc_sql($_POST['type'])); $post_id = strip_tags(esc_sql($_POST['postid'])); $gde = strip_tags(esc_sql($_POST['gde']));

The $type value is then forwarded to update_ayi_data(), which uses it as the meta key in a call to update_user_meta($current_user->ID, $rsvp_args['type'], $posts). Because there is no allow-list restricting $type to legitimate RSVP values like event_rsvp_yes or event_rsvp_maybe, an attacker can pass any arbitrary string as the meta key.

Exploitation Flow

The attack proceeds in four steps:

Step 1: Craft the malicious request. An authenticated user with Subscriber privileges sends a POST request to the WordPress AJAX endpoint (wp-admin/admin-ajax.php) targeting the ajax_ayi_action handler. The request includes type=wp_capabilities and postid=administrator.

Step 2: Bypass sanitization. The strip_tags() function finds no HTML tags in wp_capabilities or administrator. The esc_sql() function finds no SQL metacharacters. Both values pass through unchanged.

Step 3: Overwrite user meta. The update_ayi_data() function calls update_user_meta($current_user->ID, 'wp_capabilities', $posts), where $posts is constructed to include the attacker's existing subscriber role plus the injected administrator value. The resulting meta value is ['subscriber'=>true,'administrator'=>'administrator'].

Step 4: Role activation. On the attacker's next request to the WordPress site, WP_User::get_role_caps() iterates over the wp_capabilities array. It encounters the administrator key and treats it as an active role, granting the attacker all Administrator capabilities. This includes the ability to install plugins, modify themes, edit all content, manage users, and create new admin accounts.

CVSS Vector Breakdown

The CVSS 3.1 vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H reflects the severity accurately:

ComponentValueRationale
Attack VectorNetworkExploitable via standard HTTP POST
Attack ComplexityLowNo special conditions or race windows
Privileges RequiredLowSubscriber account sufficient
User InteractionNoneNo victim action needed
ScopeUnchangedStays within WordPress authorization boundary
ConfidentialityHighFull admin access to all site data
IntegrityHighCan modify any content, users, or settings
AvailabilityHighCan delete content, deactivate plugins, or lock out admins

CWE-269: Improper Privilege Management

This vulnerability is classified under CWE-269, which MITRE defines as occurring when "the product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor." The plugin modifies a user's privilege metadata without verifying that the meta key being written is a legitimate, expected key for the RSVP feature. This is a textbook instance of the weakness: the actor (a Subscriber) expands their own sphere of control to Administrator level through a mechanism the plugin never intended to expose.

Patch Information

The vulnerability was patched in version 2.3.29 of the Events Calendar for GeoDirectory plugin, delivered via WordPress Trac changeset 3533585. The fix is clean and thorough, replacing open-ended string sanitization with closed allow-lists at both the AJAX boundary and the data layer.

The Core Fix: Ternary Allow-Lists

The most critical change replaces the permissive strip_tags(esc_sql()) calls with strict ternary expressions that force each parameter into one of exactly two permitted values:

// BEFORE (v2.3.28 — vulnerable): $action = strip_tags(esc_sql($_POST['btnaction'])); $type = strip_tags(esc_sql($_POST['type'])); $post_id = strip_tags(esc_sql($_POST['postid'])); $gde = strip_tags(esc_sql($_POST['gde'])); // AFTER (v2.3.29 — patched): $action = 'add' === $_POST['btnaction'] ? 'add' : 'remove'; $type = 'event_rsvp_yes' === $_POST['type'] ? 'event_rsvp_yes' : 'event_rsvp_maybe'; $post_id = absint($_POST['postid']); $gde = !empty($_POST['gde']) ? sanitize_key($_POST['gde']) : '';

With this change, the $type parameter can only ever be event_rsvp_yes or event_rsvp_maybe. An attacker sending type=wp_capabilities would have it silently normalized to event_rsvp_maybe, which is a harmless RSVP meta key. The $post_id parameter is forced to a non-negative integer via absint(), making string injection of administrator impossible.

Date Validation Guard

The patch also added input validation for the $gde parameter:

if ( !empty($gde) && !geodir_event_is_date( $gde ) ) { wp_send_json_error( array( 'message' => __( 'Invalid date provided.', 'geodirectory' ) ) ); }

Defense in Depth at the Data Layer

Critically, the developers applied the same allow-list validation a second time inside update_ayi_data() itself. This is important because update_ayi_data() is also called from save_ayi_data() and remove_ayi_data(). Although those internal callers use hardcoded safe values today, locking down the function at its own boundary protects against future code changes that might introduce new call paths:

// Added at the top of update_ayi_data() in v2.3.29: $rsvp_args['action'] = 'add' === $rsvp_args['action'] ? 'add' : 'remove'; $rsvp_args['type'] = 'event_rsvp_yes' === $rsvp_args['type'] ? 'event_rsvp_yes' : 'event_rsvp_maybe'; $rsvp_args['post_id'] = absint($rsvp_args['post_id']); $rsvp_args['gde'] = !empty($rsvp_args['gde']) ? sanitize_key($rsvp_args['gde']) : false; if ( ! isset( $rsvp_args['action'] ) || ! isset( $rsvp_args['type'] ) || ! isset( $rsvp_args['post_id'] ) ) { return; }

Additionally, throughout the rest of the file, all remaining uses of sanitize_text_field( strip_tags(...) ) on the $gde variable were replaced with sanitize_key(), tightening input handling consistently across the class.

The fix completely eliminates the privilege escalation vector by ensuring the user meta key used in update_user_meta() can never be anything other than the two legitimate RSVP keys. The current release is version 2.3.30 as of June 4, 2026.

Affected Systems and Versions

The vulnerability affects the Events Calendar for GeoDirectory WordPress plugin in all versions up to and including 2.3.28.

DetailValue
Affected PluginEvents Calendar for GeoDirectory
Affected VersionsAll versions through 2.3.28
Patched Version2.3.29
Current Version2.3.30
WordPress Plugin Slugevents-for-geodirectory
Vulnerable Fileincludes/class-geodir-event-ayi.php
Required AuthenticationSubscriber level or above
PrerequisitePlugin must be active; user registration must be enabled (or attacker must already have an account)

Sites running version 2.3.29 or later are not affected. The plugin has 2,000+ active installs, and the parent GeoDirectory ecosystem serves 10,000+ sites with the core plugin.

Vendor Security History

AyeCode Ltd's GeoDirectory core plugin has 17 documented vulnerabilities in the Wordfence Intelligence database. The pattern of issues spans multiple vulnerability classes, with a notable concentration in authorization and privilege management flaws. Recent examples include:

VulnerabilityPluginAffected VersionPatched VersionDate
Authenticated (Contributor+) Stored XSSGeoDirectory<= 2.3.84Not specified2024
Cross-Site Request Forgery (CSRF)GeoDirectory<= 2.8.1492.8.150January 2026
Missing AuthorizationGeoDirectory<= 2.8.157Not specified2026
Authenticated (Subscriber+) Privilege EscalationEvents Calendar for GeoDirectory<= 2.3.282.3.29June 2026

The convergence of three authorization-related vulnerabilities across the AyeCode plugin ecosystem in 2024 through 2026 suggests a systemic gap in the vendor's approach to authorization and privilege checking. The CSRF vulnerability in the core plugin patched in January 2026 and the Missing Authorization issue in version 2.8.157 are consistent with the same class of weakness that underlies CVE-2026-11616.

On the positive side, AyeCode released the patch for CVE-2026-11616 before public disclosure, and the fix demonstrates a solid understanding of the correct remediation pattern (allow-lists over sanitization). The frequency of new vulnerabilities, however, suggests that sites in the GeoDirectory ecosystem should maintain rigorous update practices and consider defense-in-depth monitoring.

Threat Intelligence

As of the NVD publication date of June 9, 2026, there is no verified evidence of active exploitation in the wild for CVE-2026-11616. The Wordfence advisory does not mention confirmed exploitation, no public proof-of-concept code has been verified, and the vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) Catalog.

That said, several factors elevate the exploitation risk going forward:

  • Low barrier to exploitation. The attack requires only a Subscriber account and a single HTTP POST request. No chaining with other vulnerabilities is necessary.
  • Detailed public advisory. The Wordfence advisory provides the exact POST parameters and the resulting meta value, which significantly lowers the effort required for a threat actor to develop a working exploit.
  • WordPress plugin targeting at scale. WordPress plugin vulnerabilities are a primary target for automated exploitation campaigns. Wordfence has documented over 4.6 million attacks exploiting WordPress plugin vulnerabilities in recent 30-day periods, and privilege escalation flaws are among the most valuable to attackers because they provide persistent, high-privilege access.

No specific threat actors have been identified as targeting this CVE. The WordPress plugin exploitation landscape is dominated by automated botnet activity rather than named APT groups. Historical patterns indicate that once exploitation details are public, privilege escalation vulnerabilities in WordPress plugins are rapidly integrated into mass-scanning toolkits.

References

Detect & fix
what others miss

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