CVE-2026-12133

JoomSport <= 5.7.8 - Authenticated (Subscriber+) Missing Authorization to Arbitrary Group Deletion via season_groupdel AJAX action

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
5.7.9
Patched in
1d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=5.7.8
PublishedJune 30, 2026
Last updatedJuly 1, 2026

What Changed in the Fix

Changes introduced in v5.7.9

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

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 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_options for administrators, or delete_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:

  1. Authentication: Use wp_ajax_ (not nopriv) if the action should only be performed by logged-in users.
  2. Integrity (CSRF Protection): Use check_ajax_referer() with a specific action string to ensure the request is intentional.
  3. 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.

Research Findings
Static analysis — not yet PoC-verified

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

--- /home/deploy/wp-safety.org/data/plugin-versions/joomsport-sports-league-results-management/5.7.8/includes/posts/joomsport-post-season.php	2026-04-27 13:08:38.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/joomsport-sports-league-results-management/5.7.9/includes/posts/joomsport-post-season.php	2026-06-22 11:10:56.000000000 +0000
@@ -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.