August 11, 2026
EasyStore (Joomla) filter_sortby Pre-Authentication SQL Injection (CVE-2026–65761)
1. Overview of CVE-2026–65761
By Guidancewhite
3 min read
1. Overview of CVE-2026–65761
EasyStore is an e-commerce extension component for Joomla, distributed by developer JoomShaper. The product listing page accepts a request parameter called filter_sortby so users can choose a sort order. This value is split into a column name and a sort direction (ASC/DESC), and the direction value was inserted directly into the ORDER BY clause of the SQL query with no validation whatsoever.
Security firm mySites.guru discovered the issue and privately disclosed it to JoomShaper on July 22, 2026. The company bundled three vulnerabilities together — SQL Injection, unauthenticated order forgery, and cross-customer invoice disclosure — and silently patched them in version 2.0.2. No separate security advisory was published.
- Target: JoomShaper EasyStore (Joomla extension)
- Affected versions: 1.0.0–2.0.1
- Patched version: EasyStore 2.0.2
- CWE: CWE-89 (SQL Injection)
- CVSS 4.0: 9.3 (Critical)
2. Why the Sort Direction Is Dangerous
The basic rule of SQL Injection defense is: "never trust user input — always escape it or use parameter binding (prepared statements)." However, an ORDER BY ... ASC / ORDER BY ... DESC style sort direction is one of the few places where this principle cannot be applied directly.
Why can't it be bound?_ Parameter binding (the ? placeholder) is a mechanism for safely passing a_ value_. But ASC/DESC isn't a value — it's a keyword (reserved word) in SQL syntax. Even if you place it in a bound parameter slot, the database won't interpret it as syntax. That's why developers must hard-code a whitelist check directly into the application: "accept only ASC or DESC, reject everything else."_
EasyStore is exactly where this whitelist validation was missing. Interestingly, the sorting features for the Brand list and Collection list within the same component did have this validation implemented correctly — the check was missing only from the Product list sorting path. In other words, this wasn't a case of the developers "not knowing" the risk; it's a classic implementation-omission bug where the same logic was reimplemented in multiple places and one location was simply missed.
3. The Vulnerable Flow, in Code
The code below is a reconstructed example based on the behavior (file names, line numbers, and processing logic) described in the public vulnerability report. It is not identical to the actual source, but it's sufficient to understand the structure of the vulnerability.
① FilterHelper.php:741 — returns the direction value as-is, with no validation
// Conceptual reconstruction
public function getSortDirection($request)
{
$direction = $request->getString('filter_sortby_direction', 'ASC');
return $direction; // returned without any whitelist check
}// Conceptual reconstruction
public function getSortDirection($request)
{
$direction = $request->getString('filter_sortby_direction', 'ASC');
return $direction; // returned without any whitelist check
}The defense that should have been in place looked something like this. Reconstructing, as an example, the logic that appears to actually exist in the Brand/Collection list helper:
// What correct validation looks like (Brand/Collection helper)
public function getSortDirection($request)
{
$direction = strtoupper($request->getString('filter_sortby_direction', 'ASC'));
return in_array($direction, ['ASC', 'DESC'], true) ? $direction : 'ASC';
// What correct validation looks like (Brand/Collection helper)
public function getSortDirection($request)
{
$direction = strtoupper($request->getString('filter_sortby_direction', 'ASC'));
return in_array($direction, ['ASC', 'DESC'], true) ? $direction : 'ASC';
② ProductsModel.php:923 — the unvalidated value is concatenated directly into the query string
// Conceptual reconstruction
$sortColumn = $db->quoteName($this->getState('filter.sort_column'));
$sortDirection = $this->getSortDirection($request); // unvalidated
$query->order($sortColumn . ' ' . $sortDirection); // direct string concatenation// Conceptual reconstruction
$sortColumn = $db->quoteName($this->getState('filter.sort_column'));
$sortDirection = $this->getSortDirection($request); // unvalidated
$query->order($sortColumn . ' ' . $sortDirection); // direct string concatenationWhy doesn't
quoteName()help here? Joomla's$db->quoteName()and$db->quote()are the standard defense tools for safely escaping identifiers (column/table names) and values, respectively. But the$sortDirectionin this vulnerability is neither an identifier nor a value — it's part of SQL syntax (a keyword).quoteName('column')only wraps a column name in backticks, and wrapping the direction value withquote('value')would turn it intoORDER BY col 'DESC', which is a syntax error. So the direction value can only be defended with a whitelist, not escaping — and it's precisely that whitelist that was missing.
③ The vulnerable query, assembled conceptually
The actual exploit payload is not disclosed, but combining the two code paths above produces a final executed query with roughly this shape:
SELECT * FROM #__easystore_products
ORDER BY price {ATTACKER-CONTROLLED SQL EXPRESSION}SELECT * FROM #__easystore_products
ORDER BY price {ATTACKER-CONTROLLED SQL EXPRESSION}In the one slot where only the two words ASC or DESC should ever be allowed, an attacker-controlled arbitrary SQL expression can be inserted directly. To demonstrate the issue without extracting real data, mySites.guru said it confirmed successful injection using a time-based technique — deliberately delaying the database response under specific conditions. A response delayed by several seconds compared to a normal request serves as evidence that the injected statement executed.
4. Attack Flow
- A request reaches the product listing endpoint with a crafted
filter_sortbyparameter. - The direction segment is extracted without validation.
- The value is concatenated directly into the
ORDER BYclause. - The database executes attacker-controlled SQL as part of the sort expression.
- Success/failure is inferred via a time-based side channel (response delay), without needing to read result data directly.
5. Remediation
- Update immediately: If you're running EasyStore, upgrade to 2.0.2 or later. Because it was patched silently with no separate security notice, it's easy to overlook by only skimming the changelog.
- Review WAF rules: Confirm that SQL-keyword-based filtering rules (UNION, SLEEP, information_schema, etc.) are also applied to
filter_sortby-style parameters. - Least-privilege DB accounts: Verify the DB account used by the web application doesn't have unnecessary permissions to query
information_schemaor superuser-level access. - Review logs: Check recent access logs for requests where the
filter_sortbyparameter contained anything other than ASC/DESC — quotes, parentheses, or SQL keywords.