Summary
A security audit identified 16 authorization vulnerabilities (5 Critical, 9 High, 2 Medium) allowing cross-team data access and manipulation.
Root Cause: 1-of-N Authorization Inconsistency
Controllers that use $this->authorize() on show() skip it on update(), reopen(), destroy(). Assignment to team is authorized, but assignment to user is not.
Critical Findings
1. Ticket Update Missing Authorization (CRITICAL)
TicketsController.php:62-76 — show() calls $this->authorize('view', $ticket), but update() does NOT. Any authenticated user can modify any ticket's requester, priority, type, subject, and summary.
2. Ticket User Assignment Missing Auth (CRITICAL)
TicketsAssignController.php:15 — Team assignment checks $this->authorize('assignToTeam', $ticket), but user assignment has NO check. Any user can reassign any ticket to any user. 1-of-N inconsistency: team assignment IS checked, user assignment is NOT.
3. Lead Update — Mass Assignment + No Auth (CRITICAL)
LeadsController.php:25-30:
public function update(Lead $lead) {
$lead->update(request()->all());
}
No authorization. Combined with BaseModel having $guarded = [], any user can overwrite ALL lead columns including user_id and team_id, effectively stealing leads.
4. Team Edit/Update/Delete Missing Auth (CRITICAL)
TeamsController.php:35-59 — store() correctly calls $this->authorize('create', Team::class), but edit(), update(), and destroy() have NO authorization. Routes are outside the can:see-admin middleware group. Any agent can modify or delete any team. Note: update() regenerates the team token on every call, breaking existing invite links.
5. Default Hardcoded API Token (CRITICAL)
config/handesk.php:4:
'api_token' => env('API_TOKEN', 'the-api-token'),
Deployments not explicitly setting API_TOKEN are completely open. The API allows creating users, teams, viewing any ticket, and modifying ticket status. User listing also leaks per-agent token fields enabling agent impersonation.
Additional HIGH Findings
- Ticket reopen (TicketsController:55) — no auth, any user reopens any ticket
- Ticket escalate/de-escalate (TicketsEscalateController:9) — no auth
- Ticket tags (TicketsTagsController:9) — no auth
- Lead assign user (LeadAssignController:15) — same team-vs-user inconsistency
- Lead tags (LeadTagsController:9) — no auth
- Lead tasks (LeadTasksController:9) — no auth on view/create + mass assignment
- Task update/delete (TasksController:18) — cross-user IDOR (list is scoped, CRUD is not)
- Attachment download (AttachmentsController:11) — no ownership check, any user downloads any file
- API user creation (Api/UsersController:20) — no admin check, bypasses web admin requirement
Recommended Fixes
- Add
$this->authorize() calls to all controller methods, not just show()
- Set
$guarded on BaseModel to protect sensitive fields (user_id, team_id, etc.)
- Change default API token to a random string or require explicit configuration
- Move team routes inside the
can:see-admin middleware group
- Add ownership checks to assignment endpoints
Disclosure
Filed in good faith to improve security. No exploit code provided.
Summary
A security audit identified 16 authorization vulnerabilities (5 Critical, 9 High, 2 Medium) allowing cross-team data access and manipulation.
Root Cause: 1-of-N Authorization Inconsistency
Controllers that use
$this->authorize()onshow()skip it onupdate(),reopen(),destroy(). Assignment to team is authorized, but assignment to user is not.Critical Findings
1. Ticket Update Missing Authorization (CRITICAL)
TicketsController.php:62-76—show()calls$this->authorize('view', $ticket), butupdate()does NOT. Any authenticated user can modify any ticket's requester, priority, type, subject, and summary.2. Ticket User Assignment Missing Auth (CRITICAL)
TicketsAssignController.php:15— Team assignment checks$this->authorize('assignToTeam', $ticket), but user assignment has NO check. Any user can reassign any ticket to any user. 1-of-N inconsistency: team assignment IS checked, user assignment is NOT.3. Lead Update — Mass Assignment + No Auth (CRITICAL)
LeadsController.php:25-30:No authorization. Combined with
BaseModelhaving$guarded = [], any user can overwrite ALL lead columns includinguser_idandteam_id, effectively stealing leads.4. Team Edit/Update/Delete Missing Auth (CRITICAL)
TeamsController.php:35-59—store()correctly calls$this->authorize('create', Team::class), butedit(),update(), anddestroy()have NO authorization. Routes are outside thecan:see-adminmiddleware group. Any agent can modify or delete any team. Note:update()regenerates the team token on every call, breaking existing invite links.5. Default Hardcoded API Token (CRITICAL)
config/handesk.php:4:Deployments not explicitly setting
API_TOKENare completely open. The API allows creating users, teams, viewing any ticket, and modifying ticket status. User listing also leaks per-agenttokenfields enabling agent impersonation.Additional HIGH Findings
Recommended Fixes
$this->authorize()calls to all controller methods, not justshow()$guardedon BaseModel to protect sensitive fields (user_id,team_id, etc.)can:see-adminmiddleware groupDisclosure
Filed in good faith to improve security. No exploit code provided.