·

How to Audit WP-Cron for Suspicious Scheduled Tasks

Audit WP-Cron for suspicious scheduled tasks, trace each hook to its owner, remove confirmed persistence, and verify it stays gone.

Clock and scheduled task cards being inspected for a security problem

Last updated: September 16, 2026.

To audit WP-Cron for suspicious scheduled tasks, export a current event list, identify each hook’s owner, compare its schedule with the related plugin or theme, and remove an event only after disabling the code that created it. An unknown hook is an investigation lead, not proof of malware.

WP-Cron runs scheduled WordPress work such as publishing future posts, checking for updates, processing queues, sending reminders, and cleaning temporary data. Attackers can abuse scheduled callbacks for persistence, but abandoned plugin events and poorly named legitimate hooks are far more common than malicious tasks.

How does WP-Cron work?

WP-Cron stores scheduled hooks and asks WordPress to run due tasks when the site receives a request. It is not a continuously running operating-system service. The official WordPress cron handbook notes that scheduled publishing and update checks depend on this system.

Each event has a hook name, a next-run time, optional arguments, and sometimes a recurrence. A plugin or theme registers a callback for that hook. The event itself does not contain the full PHP action, so an audit must connect the stored hook to the code that handles it.

When should you audit WordPress scheduled tasks?

Audit WP-Cron after a compromise, when deleted spam returns, when unfamiliar administrator accounts reappear, when server resources spike on a repeating interval, or when a removed plugin continues generating requests or email. It is also useful during routine maintenance because some plugins fail to unschedule their events when deactivated.

WordPress’s scheduling documentation warns that plugins can accidentally schedule duplicate events and may leave jobs behind. Frequency, age, or an odd name alone therefore cannot classify a hook as malicious.

How do you export the current WP-Cron event list?

Use WP-CLI to create both a readable table and a JSON record. The JSON copy preserves evidence and is easier to compare after remediation. Run the commands from the WordPress installation directory with an account that can read the site configuration.

wp cron event list --fields=hook,next_run,next_run_relative,recurrence --format=table
wp cron event list --fields=hook,next_run_gmt,recurrence,args --format=json > wp-cron-events-before.json

The official wp cron event reference documents list, run, schedule, delete, and unschedule operations. Store the exported JSON outside the web root if it includes private event arguments.

Which WP-Cron hooks are normal?

Normal hooks include WordPress core update checks, scheduled-post publishing, privacy cleanup, recovery-mode maintenance, and jobs created by active plugins. Names often contain a plugin prefix, but naming conventions are voluntary. The strongest legitimacy signal is a clear match between the hook, installed code, documented feature, and expected interval.

Common core hooks can include:

  • wp_version_check
  • wp_update_plugins
  • wp_update_themes
  • publish_future_post
  • delete_expired_transients
  • wp_scheduled_delete

Do not use this short list as an allowlist. Core evolves, and plugins can register thousands of valid custom names.

What makes a scheduled task suspicious?

A hook deserves deeper investigation when no installed component references it, its arguments contain an unfamiliar domain or path, it runs unusually often without a business reason, it returns after deletion, or it appears at the same time as redirects, spam, account changes, or modified PHP files.

Useful warning signs include:

  1. No match for the hook name in active plugins, must-use plugins, themes, or custom code.
  2. Random-looking names that do not match any known namespace.
  3. Arguments containing encoded payloads, unfamiliar domains, or writable file paths.
  4. A recurrence of seconds or minutes for work that should be daily.
  5. Multiple identical events with the same hook and arguments.
  6. Jobs owned by a plugin that was removed months ago.
  7. Events recreated immediately after they are unscheduled.

None of these signals is conclusive alone. Capture the surrounding evidence before taking action.

How do you trace a cron hook to its owner?

Search the codebase for the exact hook name, then inspect where the callback is registered and where the event is scheduled. Include plugins, must-use plugins, themes, and custom snippets. If the hook is generated dynamically, search for a distinctive prefix.

grep -R --line-number --fixed-string "example_hook_name" wp-content/plugins wp-content/mu-plugins wp-content/themes

A legitimate result should explain what the event does, when it is created, and how it is removed. Confirm that the file belongs to an installed extension from a trusted source and that its checksum or release package is intact. A malicious file can imitate a legitimate prefix.

How do you inspect one hook without running it?

Filter the list rather than executing the event. Running an unknown callback may trigger the very behavior you are investigating. WP-CLI supports hook-name filtering for many cron operations, or you can export JSON and inspect it offline.

wp cron event list --hook=example_hook_name --fields=hook,next_run_gmt,recurrence,args --format=json

Do not use wp cron event run on a suspicious hook in production. If execution is necessary for analysis, restore the site into an isolated environment with outbound network controls and logging.

How do you remove a confirmed malicious WP-Cron event?

Disable or remove the code that creates the event before deleting the stored schedule. Otherwise, the callback may schedule itself again on the next page load or plugin initialization. Preserve the event export and relevant files first so the incident can be reconstructed.

Delete all events for a confirmed malicious hook:

wp cron event delete confirmed_malicious_hook

If legitimate and malicious events share a hook but use different arguments, do not delete all of them blindly. Review the command options and remove only the confirmed event in a controlled maintenance script. Re-list the hook afterward and confirm it stays absent.

What should you do with orphaned plugin events?

An orphaned event belongs to software that is no longer active or installed. It may waste resources or generate errors, but it is not automatically malware. Confirm the old plugin’s identity, check its uninstall documentation, preserve an export, and then unschedule the event if the feature is no longer required.

If the plugin is still available and trusted, temporarily restoring the same version in a staging copy may reveal its cleanup routine. Do not reinstall untrusted or vulnerable software on production simply to remove a cron entry.

How do you detect duplicate or excessive events?

Sort the exported JSON by hook, recurrence, and arguments, then look for repeated entries. Duplicate scheduling often occurs when custom code calls wp_schedule_event() without first checking wp_next_scheduled(). The WordPress developer handbook explicitly recommends that check.

List all events in CSV for spreadsheet review:

wp cron event list --fields=hook,next_run_gmt,recurrence,args --format=csv > wp-cron-events.csv

An event that runs every minute may be correct for a queue processor. Judge frequency against the documented function and actual workload, not a universal threshold.

How do you check whether WP-Cron itself is working?

Use a separate health check after the security review. A delayed task can result from low traffic, loopback failures, disabled WP-Cron, or a broken callback. WordPress checks due jobs during page requests, so a low-traffic site may execute a scheduled post later than its nominal time.

wp cron test
wp cron event list --fields=hook,next_run_relative,recurrence --format=table

If the host uses a real system cron, confirm that DISABLE_WP_CRON is intentional and that the server scheduler calls WordPress reliably. Do not switch scheduling systems during an incident unless the change is necessary and documented.

What should you verify after cleanup?

Re-export the event list, compare it with the original, and watch whether the suspicious hook returns. Check file changes, users, database entries, outbound requests, and web-server logs from the same period. A deleted event is only one symptom if an attacker still controls PHP code or an administrator account.

  1. Re-run the filtered wp cron event list command.
  2. Load several site pages and repeat the check.
  3. Wait longer than the old recurrence and check again.
  4. Review active plugins, must-use plugins, themes, and drop-ins.
  5. Verify WordPress core files with the WP-CLI checksum guide.
  6. Inspect the options table for related domains or payload fragments.
  7. Review account changes using the plugin and theme activity-log guide.

How can you prevent unsafe scheduled tasks?

Keep plugins and themes updated, remove unused software, restrict who can install or edit code, and monitor changes to scheduled hooks. A staging workflow catches extensions that create excessive or duplicate events before they reach production. Server egress controls can also limit what compromised PHP is able to contact.

Use the safe WordPress plugin update process to test updates and cron-dependent features such as email, subscriptions, backups, and scheduled publishing before rollout.

Frequently asked questions

Is WP-Cron malware?

No. WP-Cron is a standard WordPress scheduling system used by core and plugins. Attackers may abuse it for persistence, but the presence of scheduled events is normal. Investigate ownership, callback code, arguments, frequency, and related incident evidence before classifying a hook.

Can you delete every unknown cron hook?

No. Poorly documented plugins often use unfamiliar hook names, and deleting their events may stop backups, email, order processing, subscriptions, or scheduled publishing. Trace the hook to code and confirm its purpose before removal.

Why does a deleted event keep returning?

The plugin, theme, must-use plugin, or malicious code that created the event is still active. Disable the writer first, then remove the stored event. Reappearance timing can help identify which request or scheduled process recreates it.

Does disabling WP-Cron improve security?

Disabling request-triggered WP-Cron is not a security cleanup by itself. Sites can use a server scheduler instead, but due tasks still execute WordPress callbacks. If you disable WP-Cron without a reliable replacement, scheduled posts, updates, email, and maintenance jobs may fail.

← Previous Post
Next Post →