Skip to content

Repeating Tasks Ignored Company Scope

Ed Mozley edited this page Oct 18, 2026 · 1 revision

Security: repeating tasks ignored company scope

Fixed in 3.10.0 Β· Found while mapping #181 Β· Present in every release from 1.0.0 to 3.9.0 Β· Module: Tasks Β· Only installs with more than one company


The short version

On an install with more than one company, three parts of repeating tasks did not check which company a task belonged to:

  • Setting up, changing or stopping a repeat on a task.
  • Previewing a repeat - which also showed the task's title.
  • The calendar's projected occurrences - the faint future dates of repeats on a fixed schedule, with their titles.

So an analyst with Tasks access in one company could change or stop another company's repeats, or read their task titles, by sending a task number they were not allowed to see. Every other task screen and endpoint already checked; these three did not.

A single-company install was never affected. Nothing was exposed to the self-service portal or to anybody without Tasks access.

What was wrong

Every task endpoint answers "not found" for a task in a company the analyst cannot reach, through analystCanAccessTask(), and the task list filters by company through activeTenantReadFilter(). Repeats were added later, and their two endpoints loaded the task by its number alone:

$t = $conn->prepare("SELECT id, due_date, recurrence_id, parent_task_id FROM tasks WHERE id = ?");

and TaskRecurrence::project(), which draws the calendar's future occurrences, selected every active series on the install with no company filter.

The fix

  • api/tasks/save_recurrence.php and api/tasks/recurrence_preview.php check analystCanAccessTask() straight after loading the task, and answer exactly as for a task that does not exist - so another company's task number is not even confirmed.
  • TaskRecurrence::project() takes the analyst and applies the same company filter as the task list, so the calendar shows the repeats of the company you are working in (or every company you can reach under All companies), exactly like the board.

πŸ“ Files changed

File Change
🟦 api/tasks/save_recurrence.php Company check after loading the task
🟦 api/tasks/recurrence_preview.php Company check after loading the task
🟦 api/tasks/projected.php Passes the analyst to project()
🟦 includes/services/task_recurrence.php project() filters by company when given an analyst
🟩 tests/task-recurrence-company-scope.php The test below

How it was verified

php tests/task-recurrence-company-scope.php creates a throwaway analyst who can reach one company and two repeating tasks - one in that company, one in another - and calls the real endpoints over HTTP:

  • the calendar projects their company's repeat and not the other's;
  • previewing the other company's task is refused, without its title;
  • stopping the other company's repeat is refused, and it keeps running;
  • their own company's task still works;
  • positive control: an administrator who can reach every company still previews the other task, and their calendar shows their working company's repeat.

The control that matters: the same test against the code before the fix fails 6 of 10 - the calendar showed the other company's repeat, the preview returned it, and the repeat was actually stopped. With the fix, 10 of 10 pass.

What this means for you

Upgrade. If you run several companies and want to check nothing was changed: a repeat stopped by somebody who could not see the task left no record (repeat history arrives with #181), so look over the repeating tasks you rely on and confirm each is still set to repeat.

Related pages

FreeITSM

Getting Started

Modules

Multi-tenancy (planned)

Blue sky thinking

Bugs resolved

Links

Clone this wiki locally