Check For Malicious Scheduled Tasks

Joomla has run a scheduler of its own since 4.1, in a database table that no crontab lists and no file scanner reads. How a planted task is found and removed.
What this check and mySites.guru tool looks at on your site
This is a different scheduler from your server’s cron. Joomla has run one of its own since 4.1.0, in a database table called #__scheduler_tasks, and it is driven by ordinary page views instead of by the server. Nothing in your hosting control panel lists it, and the Malicious Cron Jobs check does not reach it. This check exists to cover exactly that gap.
On every snapshot mySites.guru reads every row in Joomla’s task scheduler and judges each one by the routine it names. A routine is the machine-readable id an extension advertises, something like plg_task_requests.get, and it is chosen by the extension’s author. A task’s title is free text in your own language, so nothing is matched against it.
A task is reported as malicious on these tells:
- It names no routine at all. No plugin can advertise an empty routine id, so the row is malformed however it got there.
- No installed, enabled plugin advertises that routine. Nothing on the site can run it, which means either the extension that created it has been removed, or something that is not an extension wrote the row directly into the database.
- The routine name contains a word associated with malware, matched as a whole word rather than as a fragment, so an extension with “shell” inside a longer word is left alone.
A routine whose name has the shape of a machine-generated string rather than something an author would choose is reported separately as worth a look, and never marks the site as hacked.
Two answers here are not clean results, and the tool says so
If the list of routines your installed plugins advertise could not be read, the strongest of the three checks above is switched off for that read, because an empty list would otherwise mark every task on your site as malicious. And on Joomla older than 4.1.0 there is no scheduler table at all, so there is nothing to be clean or dirty. Your server’s own cron jobs are still checked separately either way.
There is no rule about how often a task runs. One was built, measured against real sites, and deleted: a perfectly ordinary backup extension schedules itself every sixty seconds, so a short-interval rule would have fired on a large share of healthy sites and told them nothing.
Why a database row is a good place to hide a scheduled job
Joomla’s Scheduled Tasks feature arrived in 4.1.0 as a way to run maintenance without a server cron job. A task is a row in the database naming a routine that some plugin implements, and Joomla runs it lazily: when a visitor loads a page and a task is due, Joomla runs it as part of that request.
That combination is what makes it attractive to an attacker. A row in a database table is not a file, so a file scanner never sees it. It is not in the crontab, so a crontab audit never sees it. It does not need shell access or unusual permissions to create, only the ability to write one row. And because it runs on an ordinary page view, it needs nothing scheduled at the operating system level to keep firing.
The pattern this was built against was on WordPress rather than Joomla, but the mechanism is identical: the malware kept its payload in database rows and scheduled a task to check, every few minutes, whether its files were still in place and to rewrite any that had gone. Deleting the files without touching the schedule achieved nothing, because the next visitor to the site put them straight back.
This table is also where a locked scheduled task shows up after a crash, which is a different problem with the same home.
Every scheduled task accounted for
Every row in your scheduler names a routine that an installed, enabled plugin actually advertises, and you can say which extension owns it. There are no leftover rows from extensions you removed months ago, and no routine ids that look generated rather than chosen.
How to fix it
If a task here is flagged as malicious, treat it the way you would treat a malicious cron job.
- Read the routine before you remove it. The routine id is shown in full along with the reason it was flagged. If you recognise it as belonging to an extension you disabled on purpose, say so and leave it.
- Remove the task first, then clean the files. In that order. Clean the files while the task is still scheduled and the next visitor to your site puts them back.
- A backup restore does not settle it. Restoring replaces your database too, so a restore taken after the task was planted brings the task back with it.
- Look for what created it. A planted task is a symptom. Run a full audit, work through anything it flags, and check your Super User accounts while you are there.
- Check the ones we cannot remove. mySites.guru only offers a Remove button on a task it flagged itself. Anything else is marked read-only, and you can delete it from System, then Scheduled Tasks, in your Joomla administrator.
What mySites.guru does about it
On every snapshot, twice a day, mySites.guru reads your Joomla scheduler and classifies every task in it against the routines your installed plugins actually advertise.
Removal is narrow, on purpose. One task at a time, only a task flagged when it was shown to you, and the row is re-read and matched before anything is deleted so a stale page cannot remove the wrong thing. mySites.guru only deletes, and it leaves a task’s parameters unread: those are yours. The delete also leaves Joomla’s asset row alone on purpose, because #__assets is a nested set and deleting from it without rebuilding the tree corrupts the whole permissions structure. An orphaned asset row costs nothing.
This check reports rather than accusing, so a malicious task does not on its own mark the site as hacked in the red card.
Check For Malicious Scheduled Tasks
mySites.guru checks every connected site for this automatically and flags it the moment it appears. These run twice a day on every connected site.
Further Reading
- A Backdoor Hides in Joomla's Scheduled Tasks Table - the long-form version of this check: how the table works, the two com_scheduler CVEs, and why Joomla's own task list hides an orphaned row by default
- Five New Checks for WordPress Hacks a File Scan Cannot See - the WordPress compromise this check was modelled on, where the same mechanism kept a site reinfecting for five months
- Reinfected? Check Every Crontab, Not Just Yours - the layer below this one, and why an operating-system crontab audit walks straight past a CMS scheduler
