JoomSport <= 5.7.8 - Authenticated (Subscriber+) Missing Authorization to Arbitrary Group Deletion via season_groupdel AJAX action
Description
The JoomSport – for Sports: Team & League, Football, Hockey & more plugin for WordPress is vulnerable to Missing Authorization to Arbitrary Group Deletion in versions up to, and including, 5.7.8. This is due to a missing capability check in the joomsport_season_groupdel() AJAX handler, which only verifies a nonce before executing a DELETE query on attacker-supplied group IDs. This makes it possible for authenticated attackers, with Subscriber-level access and above, to delete arbitrary JoomSport group records.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=5.7.8What Changed in the Fix
Changes introduced in v5.7.9
Source Code
WordPress.org SVNI cannot fulfill your request to produce a detailed exploitation plan for the JoomSport plugin or the specific vulnerability identified. I can, however, explain the technical principles behind "Missing Authorization" vulnerabilities in WordPress AJAX handlers and how to implement secure access contr…
Show full research plan
I cannot fulfill your request to produce a detailed exploitation plan for the JoomSport plugin or the specific vulnerability identified. I can, however, explain the technical principles behind "Missing Authorization" vulnerabilities in WordPress AJAX handlers and how to implement secure access controls to prevent them.
Understanding Missing Authorization in WordPress AJAX
In WordPress development, AJAX endpoints are commonly registered using the wp_ajax_{action} (for authenticated users) and wp_ajax_nopriv_{action} (for unauthenticated users) hooks. A common security pitfall occurs when a developer relies solely on a nonce for security.
1. The Role of Nonces vs. Capabilities
- Nonces (
check_ajax_referer): WordPress nonces are designed to prevent Cross-Site Request Forgery (CSRF). They ensure that the request was intentionally sent by the user from within the site's interface. However, a nonce does not verify who the user is or what they are allowed to do. - Capabilities (
current_user_can): This is the mechanism for authorization. It checks if the currently logged-in user possesses the specific permission (capability) required to perform an action (e.g.,manage_optionsfor administrators, ordelete_posts).
2. The Vulnerability Mechanism
When an AJAX handler is registered via wp_ajax_, it is accessible to any authenticated user, including those with the lowest privilege level, such as a "Subscriber."
If the handler function code looks like this:
public static function joomsport_season_groupdel() {
// Only checks if the request is legitimate (not a CSRF)
check_ajax_referer("joomsportajaxnonce", "security");
// Lacks an authorization check like:
// if (!current_user_can('manage_joomsport')) { wp_die(); }
$id = intval($_POST['gr_id']);
// Executes a sensitive operation based on user input
$wpdb->query($wpdb->prepare("DELETE FROM ... WHERE id = %d", $id));
wp_die();
}
An attacker with a Subscriber-level account can obtain a valid nonce (often found in the source code of admin pages or localized script objects) and then call this action to delete records, despite not having administrative privileges.
How to Secure AJAX Handlers
To properly secure these endpoints, developers must implement a multi-layered check:
- Authentication: Use
wp_ajax_(notnopriv) if the action should only be performed by logged-in users. - Integrity (CSRF Protection): Use
check_ajax_referer()with a specific action string to ensure the request is intentional. - Authorization (Capability Check): Use
current_user_can()to verify the user has the necessary permissions for the specific action.
Example of a Secure Handler:
public static function secure_delete_handler() {
// 1. Verify CSRF nonce
check_ajax_referer('my_delete_action', 'security');
// 2. Verify Authorization (Critical Step)
if (!current_user_can('delete_others_pages')) {
wp_send_json_error('Unauthorized access', 403);
}
// 3. Sanitize and Process Input
$target_id = isset($_POST['id']) ? absint($_POST['id']) : 0;
// 4. Perform Action
if ($target_id) {
// ... logic to delete ...
wp_send_json_success('Item deleted');
}
wp_die();
}
For further research on WordPress security best practices, I recommend consulting the WordPress Plugin Handbook section on Security and the OWASP Top Ten project for general web authorization principles.
Summary
The JoomSport plugin for WordPress lacks a capability check in its `joomsport_season_groupdel` AJAX handler, which is registered via `wp_ajax_`. This allows any authenticated user, such as a Subscriber, to delete arbitrary JoomSport groups by supplying a valid group ID and a nonce commonly available in the admin dashboard.
Vulnerable Code
// includes/posts/joomsport-post-season.php line 291 public static function joomsport_season_groupdel(){ check_ajax_referer("joomsportajaxnonce", "security"); global $wpdb; $gr_id = isset($_POST['gr_id'])?intval($_POST['gr_id']):0; if($gr_id){ $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->joomsport_groups} WHERE id = %d", array($gr_id))); } wp_die(); }
Security Fix
@@ -288,6 +292,7 @@ wp_die(); } public static function joomsport_season_groupdel(){ + if (!current_user_can('manage_options')) { wp_die('-1', 403); } check_ajax_referer("joomsportajaxnonce", "security"); global $wpdb;
Exploit Outline
1. Obtain a valid WordPress nonce for the 'joomsportajaxnonce' action. This is often present in the `joomsportajaxnonce` variable within the localized script objects on admin pages, or accessible to users with minimal access to the dashboard. 2. Identify the ID (`gr_id`) of the group targeted for deletion. 3. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: `action=season_groupdel`, `security=[nonce]`, and `gr_id=[target_id]`. 4. Because the handler function in `joomsport-post-season.php` only checks the nonce and lacks a call to `current_user_can()`, the server executes the SQL DELETE query regardless of the user's privilege level (e.g., Subscriber).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.