Check For Malicious Cron Jobs

A cron job that quietly re-downloads malware after every clean-up is why a hacked Joomla site keeps reinfecting itself. How to find one and remove it safely.
What this check and mySites.guru tool looks at on your site
Cron is the task scheduler built into every hosting account. It runs a command on a timetable and has no opinion about what that command does, which makes it the most durable foothold an attacker can leave on a compromised Joomla site. This check reads the account’s own crontab, the system crontab at /etc/crontab, the drop-in directory at /etc/cron.d/, and the run-parts script directories (/etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/), and classifies whatever it can read.
A job is only ever flagged as malicious on tells that have no innocent explanation in a website’s cron: downloading something and piping it straight into a shell, decoding an encoded blob and executing the result, fetching from a bare IP address instead of a hostname, running a program out of /tmp or /dev/shm, running a hidden dot-prefixed file, making a file executable from cron, or clearing shell history. Ordinary jobs, a CMS scheduler trigger, a backup tool, certbot, rsync, a database dump, are left alone because they read as exactly what they are.
This only works where your hosting permits it
Reading or changing cron needs the same access an attacker would need to plant a job. Plenty of hosts do not grant that, so a clean result on a locked-down host means “we could not look,” not “there is nothing there.” Treat this as one more place to check, not proof that cron is clean.
What turns a clean-up into a losing game
A cron job is what turns a one-off clean-up into a losing game, and reinfected? check every crontab, not just yours is the fuller story of why. You can remove every malicious file from a site and, if a scheduled job is still set to fetch and rewrite them, they are back within the hour and the clean-up looks like it simply failed. We have seen a job running every five minutes whose only job was to check whether a hidden webshell was still in the web root and, if it had gone, copy a stashed spare back into place from a .cache directory. Removing the webshell without finding that job would have looked like a success right up until the next five-minute mark.
The blind spot is that most site owners only ever look at their own account’s crontab. On one server we found a backdoor sitting in /etc/cron.daily/, disguised as a hosting-panel sync script, running as root every day and dropping a webshell into practically every site on the box. Its payload was a single line that downloaded a script from an IP address written in hexadecimal and piped it into a shell, so nothing was ever written to disk for a file scanner to catch. Because cron lives on the server rather than in a site’s files, neither a file scanner nor the CMS itself can see it.
There are also two schedulers above the operating system that a server-side cron check does not cover: WordPress’s WP-Cron, stored in the wp_options table, and Joomla’s own Scheduled Tasks, stored in #__scheduler_tasks. Those are separate surfaces and need their own review.
Every job accounted for, nothing hidden
A clean crontab contains only jobs you or your host can account for: your CMS’s own scheduler, a backup tool, certbot renewal, a log rotation, a database dump. Every entry runs a recognisable command against a recognisable target, none of them download-and-execute, none of them run from a temporary directory, and nothing is hidden behind a dot-prefixed filename or an obfuscated one-liner.
How to fix it
- Get access to the crontab. Run
crontab -lover SSH, or use your host’s panel, cPanel’s Cron Jobs page or Plesk’s Scheduled Tasks. That only shows your account’s own jobs, so also ask your host, or use SSH access if you have it, to check/etc/crontab,/etc/cron.d/and the four run-parts directories. - Read every line before touching anything. Look for the tells above: a download piped into a shell, a decoded and executed blob, a bare-IP fetch, execution from
/tmpor/dev/shm, a hidden dot-file, or achmod +xon something that should not need it. - Remove the malicious job first, then clean the files. In that order. Clean the files while the job is still scheduled and it simply puts them back, often within minutes.
- Do not rely on a backup restore to fix this. Restoring replaces your files and database. It does not touch the server’s crontab, so a scheduled reinfection survives the restore untouched and starts again.
- If you find anything under
/etcowned by root, get your host involved. Anything there was placed by something running as root, which means the compromise reaches beyond your hosting account and cannot be cleaned from inside it alone. - Then find what installed it. A malicious cron job is a symptom, not the whole story. Scan the site’s files for what dropped it, and check every other site you run on the same server or hosting account.
What mySites.guru does about it
On every snapshot, twice a day, mySites.guru reads what your hosting account lets us see, in the same order and against the same tells described above, and flags any job that matches. We show you the exact line, why it was flagged and, where we can tell, whether it came from the system or from your own account, so you know whether it is yours to remove or your host’s.
Check For Malicious Cron Jobs
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.