Skip to content

Security: Missing authorization check in ThreadXHR::listTicketThreadCollectionXHR() (IDOR) #720

@lighthousekeeper1212

Description

@lighthousekeeper1212

Summary

The listTicketThreadCollectionXHR() endpoint in Controller/ThreadXHR.php is missing the isTicketAccessGranted() authorization check that is consistently applied across all 15 other ticket-related endpoints in the codebase. This allows any authenticated agent to read ticket thread history of any ticket in the system, regardless of their access level restrictions.

Affected Endpoint

  • Route: GET /member/{locale}/ticket-panel/threads/ajax/{ticketId}
  • Route name: helpdesk_member_thread_collection_xhr (Resources/config/routes/private.yaml line 255)

Issue

ThreadXHR::listTicketThreadCollectionXHR() fetches a ticket by ID and returns all threads without calling isTicketAccessGranted():

// Controller/ThreadXHR.php - lines 20-36
public function listTicketThreadCollectionXHR($ticketId)
{
    // ...
    $ticket = $entityManager->getRepository(Ticket::class)->findOneById($ticketId);
    if (! empty($ticket)) {
        // Missing: isTicketAccessGranted() check
        $paginationResponse = $this->ticketService->paginateMembersTicketThreadCollection($ticket, $request);
        return new Response(json_encode($paginationResponse), 200, ...);
    }
}

Every other ticket endpoint checks authorization:

  • TicketXHR.php (7 locations): bookmarkTicketXHR, updateTicketAttributes, updateTicketDetails, saveTicketLabel, etc.
  • Thread.php (3 locations): saveThread, editThread, downloadAttachment
  • Ticket.php (5 locations): read, trash, delete, downloadZip, downloadAttachment

Impact

An agent with restricted access (TEAM_ACCESS or INDIVIDUAL_ACCESS) can enumerate sequential ticket IDs to read thread history of tickets outside their authorized scope.

Suggested Fix

Add the standard authorization check:

if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
    throw new \Exception('Access Denied', 403);
}

This is consistent with the pattern used in all other ticket endpoints.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions