How to Compare WordPress Files Changed After an Incident
Compare WordPress files with the right release checksums, preserve a snapshot first, and investigate core, plugin, theme, and custom-code changes.
After a security alert or emergency cleanup, an administrator notices recently modified WordPress files and wants to know whether they contain unauthorized code. File timestamps cannot answer that on their own. Updates, deployments, backup extraction, migrations, and an attacker changing metadata can all produce similar dates. Replacing everything before recording the current state can also erase evidence that would help explain how the changes happened.
Short answer: preserve a protected copy of the files and database, record the site version, locale, installed components, and deployment history, then compare files with a trusted, matching baseline. WP-CLI can verify WordPress core and supported WordPress.org plugins against published checksums. A mismatch is a finding to investigate—not an automatic instruction to delete or overwrite the file. Premium plugins, custom themes, uploads, configuration, and database content require a baseline owned by the site or its vendor.
If the evidence points to unauthorized access, content changes, or a compromised account, use the WordPress hacked-site response guide as the incident framework. For restore planning, see the website backup guide; a recovery set needs both files and the separate database.
Decide what you are trying to establish
Replace “Which files have the newest dates?” with narrower questions: which component changed, does that change match an approved release or deployment, when did it first appear, and can it execute on a public request? A host alert, scanner result, Search Console example, or customer report is a lead. Record its source and observation time without treating any one report as a complete inventory.
Define the scope before running commands. A WordPress installation includes core, plugins, themes, must-use plugins, drop-ins, uploads, configuration, build artifacts, and database content. A core checksum check does not tell you whether wp-content/uploads contains unexpected PHP, whether a premium plugin was modified, or whether the database contains injected values. State what was checked, what was outside scope, and why; otherwise, “core verified” may be misread as “the entire site is clean.”
Agree on the production change window with the site owner and host. If the site is taking orders or serving users, a snapshot, cleanup, or restore can affect evidence and availability. For suspected data theft, regulated information, or a legal dispute, involve qualified incident-response and legal advisers rather than describing an ordinary file copy as a forensic image.
Preserve the current state before comparing
Ask the host to preserve the files and database before cleanup, replacement, updates, or a restore. Retain available access, error, authentication, deployment, and hosting-panel logs as well. Keep the copy outside the public webroot with restricted access. Database dumps, configuration, cookies, and credentials should not be attached to a public support ticket. Record who collected the material, the time and time zone, storage location, site environment, WordPress version, and installation language.
Build an expected-component inventory from an authorized source: deployment records, a lockfile or manifest, the vendor’s package, an internal repository, or a pre-incident host snapshot. Do not download the “latest” release and compare it with an older installation without checking the versions. Legitimate release differences can create a large number of mismatches and obscure the changes that matter.
Use a read-only copy or a host-approved process where possible. Tell the operator if the comparison itself could update files or run application code. Keep a working copy separate from the original snapshot, and restrict who can access both. If a formal evidence process may be required, ask the relevant specialists how to collect and preserve the material before making changes.
Verify core against the matching release
WP-CLI’s wp core verify-checksums compares core files with WordPress.org checksums. Run it from the intended installation—not an unintended staging copy or a different site on the same host. Record the installed version and locale, then pass the matching values when needed:
wp core version
wp core verify-checksums --version=<installed-version> --locale=<installed-locale>
Replace the placeholders with the recorded values; do not type the angle brackets literally. Read and retain the complete output, including missing, unexpected, or mismatched files. If the command fails because the version or locale is wrong, correct the parameters and rerun it. Do not immediately fetch new files just to make the first result disappear.
A successful check means the checked core files match the reference for that release and locale. It does not cover every file on the hosting account, the database, or the site’s access paths. A mismatch is not proof of malware either: an old installation may contain approved patches, a managed host may customize a package, or a deployment may have changed files. Match findings with change tickets and a trusted release before deciding what to replace.
The official WP-CLI core verification reference describes its scope. Do not use an insecure option that disables certificate checks. If you need to include root items, understand that this is not a whole-site integrity scan and may surface unrelated host files.
Check plugins—and understand what cannot be verified
For plugins distributed through WordPress.org, wp plugin verify-checksums --all can compare installed files with available published checksums. Review the WP-CLI plugin verification documentation and preserve the output. Checksum coverage does not extend to every premium, custom, or vendor-distributed plugin. A “no checksum available” result means you need another baseline; it does not, by itself, mean the plugin is malicious.
For premium and private software, obtain the package through the vendor account or an approved company repository. Match the product, exact version, release date, and package hash if the vendor provides one. Compare against a known-good deployment artifact—not a download from the site currently under investigation. Do not upload private source code or customer backups to a public comparison service without the owner’s permission.
Review the active theme and child theme, must-use plugins, drop-ins such as object-cache files, wp-config.php, .htaccess, Nginx configuration, CDN rules, and assets generated by the site’s build process. Those items may not be covered by core checksums. If there is no baseline, document the uncertainty and ask the component owner or host to approve a trusted reference. Do not call every customization malware simply because it is absent from a standard WordPress package.
Compare additional files without trusting timestamps alone
Once the clean package is confirmed, compare targeted files on a copy or staging environment. Record relative paths, sizes, hashes, ownership, permissions, and content differences. sha256sum can create fingerprints for repeat comparisons; a diff tool can show changed lines. Avoid printing secrets from configuration files into shared logs. For binaries or minified assets, use an appropriate hash or file-analysis tool; an unreadable diff is not evidence that the file is safe.
Timestamps are useful when correlated with deployment, backup, login, update, and ownership records. They are not proof: extraction or copying can reset them, servers may use different time zones, and an attacker can manipulate metadata. Do not sort by date and delete everything that looks new. Record clock differences before building a timeline from host logs, Search Console, and server files.
Check unexpected files in the core tree, wp-content, webroot, and host-managed locations that are in scope. A new file may be a cache, host configuration, update artifact, or legitimate operational tool. Verify its owner and how it was created. Do not execute a suspicious file to “see what it does”; preserve a copy safely and ask a specialist to inspect obfuscated code, loaders, or commands if necessary.
Decide whether to document, restore, or escalate
Classify findings as: matching the official release; approved with an identifiable owner and change record; unexplained; missing; or additional without a verified source. For each item, record its path, baseline, supporting evidence, owner contacted, risk, and decision. A clean scanner result does not make a file trusted, and an unfamiliar filename alone is not a reason to delete it.
If a standard core or plugin file is confirmed to have changed without approval, consider reinstalling that component from a trusted source after preserving evidence and controlling the entry point. Do not overwrite files blindly if the installation has local patches or required custom code; compare with the repository and test the change in staging. If a plugin or theme is recreating a backdoor, replacing its files without addressing the account, scheduled task, or configuration that writes them may only provide a temporary fix.
For a changed server configuration, custom theme, must-use plugin, or database value, involve the component owner and host. Contain access that is confirmed unauthorized, fix the underlying weakness, and rotate exposed credentials from a clean device under an agreed plan. If you cannot distinguish a valid local change from injected code, do not guess on production—escalate to the hosting administrator or an incident-response professional.
Verify recovery and keep a clean baseline
After restoring an approved component, rerun the checksum check with the same version and locale. Compare the before-and-after output; every remaining difference should have an owner and explanation. Test administrator access, public pages, forms, checkout if applicable, essential plugins, permissions, scheduled jobs, and the URLs that triggered the alert. Review new logs to see whether files change again. If they do, identify the writing process rather than repeating the reinstall.
Keep the new trusted baseline with an owner, date, component versions, list of custom files, and agreed hashes. Maintain a separate backup and test restoration in a non-public environment. Schedule updates, minimize privileges, use individual hosting access, and record deployments. A documented baseline makes the next integrity review far more useful than a list of dates without context.
Frequently asked questions
Does a successful checksum check prove my site has no malware? No. It confirms only that the checked files match a reference for the selected version and locale. Extra files, premium plugins, themes, uploads, database content, accounts, scheduled jobs, servers, and CDNs need separate review.
Does a recent file timestamp prove an attacker changed it? No. Updates, deployments, restores, extraction, migration, and synchronization can change dates. Correlate timestamps with logs, release history, hashes, and the change owner.
Can I replace every file that fails verification? Not before preserving a snapshot and confirming the source. Check the exact package, record the results, account for customization, and test recovery on a copy. Replacing files does not stop the process that changed them.
What should I check if core and plugin checksums pass but the symptoms remain? Expand the investigation to custom plugins and themes, must-use plugins, uploads, server configuration, database content, accounts, cron jobs, caches/CDNs, and third-party scripts. A checksum result is not a full-site audit.
If files keep changing, an unknown account appears, or a harmful page remains public, contact the website security response team. Provide the recorded versions, checksum output, timeline, and actions taken—never passwords, tokens, or customer database dumps in a public channel.
Does any of this look like your website?
Tell us on WhatsApp. We look first, explain what needs fixing, then you decide. For a fuller picture, request the free audit.
Related articles.
One Website Page Redirects to an Unfamiliar Domain: How to Trace It
When one URL redirects visitors, record the first response, map it to a WordPress object, and distinguish page-level rules from server, script, or compromise.
WordPress Redirects Only on Mobile: How to Investigate
A WordPress redirect that appears only on mobile needs safe reproduction, log, cache, server and code checks, then verification without exposing visitors.
Gambling Links in a WordPress Database: Audit wp_posts and wp_options
Search for unauthorized gambling links in WordPress with a protected backup, read-only queries, record review, and cleanup that respects serialized data.