# guide

How to find recently modified files on a hacked WordPress site

Updated October 2026

WordPress installs are mostly static: core, themes and plugins change only when you update them. So the files that changed in the last few hours or days are where an infection is. This guide shows how to list them reliably, scan just those files, and confirm what the attacker touched.

Use change time, not modification time

find -mtime looks at the modification time, which malware routinely resets with touch to match neighbouring files. The inode change time (ctime) cannot be set from user space, so -cmin and -ctime are the ones to trust.

$ find /var/www/html -type f -cmin -60        # changed in the last hour
$ find /var/www/html -type f -ctime -2         # changed in the last two days
$ find /var/www/html -type f -newerct '2026-10-20 00:00' -ls   # since a date

Sort by change time to see the sequence of events, which often reveals the loader first and the dropped files after it:

$ find /var/www/html -type f -ctime -7 -printf '%C+ %p\n' | sort

A file whose mtime is old but whose ctime is recent is a strong signal: someone changed it and then faked the timestamp.

$ stat -c '%n  mtime=%y  ctime=%z' /var/www/html/wp-includes/images/wp-img.php

Scan only the changed files

WPSniffer reads file paths from standard input, so the list from find goes straight into a YARA scan. Use -print0 so odd filenames survive the pipe:

$ find /var/www/html -type f -cmin -60 -print0 | wpsniffer malware-scan

This is the fastest scan you can run during an incident: seconds instead of minutes, and it ignores the thousands of untouched files. For a report you can share:

$ find /var/www/html -type f -ctime -3 -print0 | wpsniffer malware-scan --match-all \
    --output-path ~/changed-files.csv \
    --output-columns filename,signature_id,signature_description,rule_reference,matched_text

WPSniffer is a two-minute install; see the docs.

Verify core and plugin checksums

Timestamps find what changed; checksums find what is wrong. If WP-CLI is available, compare every core file against the official release and every plugin from the WordPress directory against its published version:

$ wp core verify-checksums --path=/var/www/html
$ wp plugin verify-checksums --all --path=/var/www/html

Any file reported as modified or unexpected in wp-admin, wp-includes or a directory-hosted plugin is almost certainly injected. The exceptions are files you edited on purpose, and wp-config.php and .htaccess, which are not covered by checksums and deserve a manual read.

Without WP-CLI, download the same WordPress version from wordpress.org and diff -r the wp-admin and wp-includes directories.

Check the usual hiding places

A few locations deserve a look regardless of timestamps, because they run code automatically or are easy to overlook:

  • wp-content/mu-plugins/: must-use plugins load on every request and do not appear in the plugins screen.
  • wp-content/uploads/: should contain no PHP at all. See finding webshells in uploads.
  • wp-config.php, index.php, wp-load.php and the active theme's functions.php and header.php: favourites for injected includes and redirects.
  • .htaccess files anywhere in the tree, for redirects and PHP handler tricks.
  • The /tmp and /dev/shm directories, where droppers stage payloads.
  • The database: the wp_options table (siteurl, home, active_plugins) and wp_posts for injected scripts and spam. A file scanner does not see these.

Next steps

With the list of changed and flagged files in hand, follow the cleanup guide: confirm, quarantine, find the entry point, restore, rotate secrets and re-scan. Then make the recent-files check routine with a scheduled scan that covers only files changed since the previous run.