Files or users reappear at regular intervals even when no administrator is active. A malicious WordPress cron event, Action Scheduler job or server cron can execute the persistence code.
Do not delete every unfamiliar event. WooCommerce, backups, email and updates rely on scheduled work.
Match recurrence to schedule
Create a timeline of file/user changes and compare it with scheduled intervals. Account for delayed WP-Cron execution: on low-traffic sites, a due job may run when the next visitor arrives.
List WordPress events from an authorised environment:
wp cron event list --fields=hook,next_run_gmt,next_run_relative,recurrence
Save the output before modifying events. Do not run suspicious hooks manually.
Attribute every questionable hook
Search verified plugin/theme source for the hook name and callback. Check whether the owning component is active, maintained and expected to schedule it.
Generic or random names, callbacks in uploads, remote code retrieval and jobs with no accountable owner deserve deeper review. A legitimate event can also be hijacked through modified callback code.
Preserve event arguments carefully; they can contain personal or secret data.
Inspect Action Scheduler separately
WooCommerce and many plugins use Action Scheduler rather than basic WP-Cron. Review pending, failed and recurring actions, their hooks, groups and logs.
Do not purge a large queue blindly. It may include payment, subscription, webhook, email or stock tasks.
Quarantine evidence of a malicious action, then remove only confirmed persistence and repair its registering code.
Check server and hosting cron
cPanel, Plesk and VPS cron can invoke PHP files or URLs independently of WordPress. Export scheduled commands and record user, interval and creation evidence.
Do not execute an unknown command or follow its URL. Preserve it as text and inspect the referenced file offline.
Check neighbouring sites under the same account; one cron can target several document roots.
Remove the registrar before the event
If malicious code schedules the task on every request, deleting the event first only makes it return. Contain the site, preserve the code and remove/replace the registrar from verified sources.
Then unschedule the exact hook and arguments through safe WordPress tools. Delete related options/transients only after confirming ownership.
For custom code, add no new cleanup script to production until it has been reviewed and a database backup exists.
Inspect the callback’s external dependencies
A scheduled hook may look legitimate while its modified callback retrieves instructions from an unknown domain or reads a payload from the database. Trace the callback statically and record outbound hostnames, timeouts and file destinations.
Block a confirmed malicious destination at an appropriate egress or application layer as temporary containment, but do not rely on the block as cleanup. The code could change domains or use a stored payload. Remove the compromised callback and review other scheduled events registered by the same component.
Restore a controlled cron mechanism
Confirm legitimate scheduled posts, updates, backups and WooCommerce actions remain. If using system cron with DISABLE_WP_CRON, verify the replacement runner before enabling the constant.
Stagger heavy security scans and backups, but do not delay time-sensitive order tasks without understanding them.
Document the expected schedule baseline.
Prove the job no longer returns
Monitor events, files and users across several previous recurrence intervals. Trigger normal visitor cron and the authorised system runner.
Check PHP and access logs for attempts to call the removed path. Confirm no equivalent hook appears under a new name.
When specialist cleanup is needed
Request help when hooks return, callbacks are obfuscated or the queue contains ecommerce actions. Send hook names and timestamps with arguments redacted.
A complete cleanup removes the scheduled event, the code that registers it and the access route that introduced both.