
Docker-based lab for reproducing CVE-2026-42647, an unauthenticated time-based blind SQL injection in the JoomSport WordPress plugin via the sortf parameter. Includes vulnerable and patched targets for comparison.
sortfThis repository contains a local Docker lab for reproducing and validating CVE-2026-42647, an unauthenticated SQL injection vulnerability affecting the WordPress plugin JoomSport - for Sports: Team & League, Football, Hockey & more.
The vulnerable behavior occurs in the player list sorting feature. A public visitor can control the sortf query parameter, which is used to build an SQL ORDER BY clause. In vulnerable versions, the value is sanitized as text and wrapped in backticks, but it is not validated against a strict allowlist before being appended to the SQL query.
This lab compares two JoomSport versions:
| Service | JoomSport version | Purpose | URL |
|---|---|---|---|
vuln | 5.7.6 | Vulnerable comparison target | http://localhost:8081 |
patched | 5.7.8 | Patched comparison target | http://localhost:8082 |
The public advisories identify versions before 5.7.8 as affected and 5.7.8 as the fixed version. This lab uses 5.7.6 as the vulnerable target because a 5.7.7 source tag was not available in the WordPress.org plugin SVN tag listing at the time this lab was prepared.
The demonstrated vulnerability chain is:
Unauthenticated visitor
→ JoomSport season player list route
→ attacker-controlled sortf parameter
→ unsafe dynamic ORDER BY construction
→ SQL expression execution
→ measurable database delay in vulnerable version
→ patched version rejects the injected sort field and falls back to a safe allowlisted field
This lab validates the vulnerability as a time-based blind SQL injection. It does not perform database dumping, credential extraction, data modification, or destructive SQL operations.
This lab is designed for controlled local research, source-level understanding, and portfolio demonstration only.
| Claim | Evidence | How to verify in this lab |
|---|---|---|
| JoomSport before 5.7.8 is reported vulnerable to unauthenticated SQL injection. | Public advisories identify JoomSport < 5.7.8 / <= 5.7.7 as affected. | Review the References section and compare the vulnerable/patched services. |
| JoomSport 5.7.8 is the fixed version. | Public advisories and source comparison show that 5.7.8 validates the sortf value before building the ordering expression. | Inspect class-jsport-playerlist.php in both versions. |
The affected parameter is sortf. | The vulnerable player list code reads classJsportRequest::get('sortf'). | Run the PoC and observe the injected sortf request. |
| The vulnerable code builds a dynamic SQL ordering value from user input. | In the vulnerable version, sortf is used to build $options['ordering']. | Inspect sportleague/classes/objects/class-jsport-playerlist.php. |
The SQL sink is an ORDER BY clause. | The generated $ordering value is later appended into an SQL query with ORDER BY. | Inspect sportleague/base/wordpress/classes/class-jsport-getplayers.php. |
| The patch uses an allowlist-style fix. | The patched version introduces allowed static columns and expected dynamic field patterns before using the sort field. | Compare JoomSport 5.7.6 and 5.7.8 source. |
| The lab demonstrates time-based blind SQL injection. | The vulnerable target delays when an injected SLEEP() expression is used; the patched target does not. | Run python3 poc/poc.py http://localhost:8081 http://localhost:8082. |
This lab uses JoomSport 5.7.6 as the vulnerable comparison target because the public fixed version is 5.7.8 and a 5.7.7 source tag was not available in the WordPress.org plugin SVN tag listing when the lab was prepared.
The lab does not claim that 5.7.6 is the only vulnerable version. It is used as a reproducible vulnerable baseline for comparing vulnerable behavior against the patched 5.7.8 behavior.
The lab focuses on the sortf parameter in the player list sorting flow.
The demonstrated impact is time-based blind SQL injection. The lab does not demonstrate:
Error-based or boolean-based behavior may be possible depending on database behavior, application configuration, and response differences, but this lab does not rely on those techniques. The primary proof is timing-based.
The root cause is unsafe construction of a dynamic SQL ORDER BY clause from the sortf request parameter.
The vulnerable code path starts in:
sportleague/classes/objects/class-jsport-playerlist.php
Inside the player list loading logic, JoomSport reads the request parameter:
sortf
and uses it to construct:
$options['ordering']
The relevant vulnerable source pattern is:
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 issue is not primarily the sortd parameter. The sortd value is restricted to:
ASC
DESC
The issue is the sortf parameter because it controls the SQL identifier/expression position used for sorting.
The dangerous expression is:
"`".classJsportRequest::get('sortf')."`"
The code places attacker-controlled input inside a MySQL identifier context and then passes it forward as an SQL ordering fragment.
The code applies:
sanitize_text_field()
but sanitize_text_field() is not SQL identifier validation. It is designed for cleaning text, not for safely constructing SQL syntax.
The vulnerable code also wraps the user-controlled sort field in backticks. However, backticks are not a security boundary when the attacker can influence the identifier content. If an attacker can inject a backtick into the value, they can break out of the intended identifier context.
The generated ordering value is later passed into the player retrieval query and appended into an SQL ORDER BY clause in:
sportleague/base/wordpress/classes/class-jsport-getplayers.php
The sink pattern is:
$query .= ' ORDER BY '.($ordering);
This creates the vulnerable data flow:
sortf request parameter
→ classJsportRequest::get('sortf')
→ $options['ordering']
→ $ordering
→ ORDER BY <attacker-influenced expression>
The security issue is that the application treats a user-controlled request parameter as a SQL identifier/expression without first validating it against a strict allowlist.