File Integrity Alert Fired — Investigate and Restore
GuardPress’s File Integrity Monitor flagged a file as modified, deleted, or newly added in /wp-admin/, /wp-includes/, a plugin, theme, or your uploads/ directory. Most alerts have a routine cause (a plugin or theme just auto-updated, you ran a deploy, WordPress installed an update overnight) but a small minority are real compromises. This runbook is the triage flow: identify the file category in 60 seconds, rule out routine causes, then either Restore from the canonical WordPress.org source or escalate.
What a File Integrity Alert Actually Means
The File Integrity Monitor runs on the guardpress_daily_scan cron hook and walks WordPress core, active plugins, the active theme, and the uploads/ directory. For each file it computes a SHA-256 hash via hash_file() and compares against the previous scan’s baseline. When a hash changes, the file appears as a row in the gp_file_changes table with one of three statuses, and a consolidated alert email is sent at the end of the scan (one email per scan since 1.6.24, not one per file).
The three statuses you’ll see in the File Monitor admin page:
- Added — the file didn’t exist at the previous scan and now does. Most common cause: a plugin update added a new file; less common but worth investigating: a webshell uploaded to
uploads/. - Modified — the file existed before, still exists, but its content hash changed. Most common cause: plugin / theme / core update.
- Deleted — the file existed before and is now gone. Most common cause: a plugin update removed a file that the new version no longer needs.
The alert is a signal, not a verdict. The signal is reliable (the hash comparison is exact). The interpretation is what this runbook is for.
Step 1: Rule Out Routine Causes
In the overwhelming majority of cases, file integrity alerts have an easy-to-recognise legitimate source. Check these first before assuming the worst:
Did a plugin or theme update just run?
Open WP Admin → Dashboard → Updates and scroll to the “Recently Installed Plugins” / “Recently Updated” sections. If anything updated in the last 24 hours, the file changes are expected. WordPress’s auto-updates run silently on a daily schedule for plugins and themes that opted in, so this is a more common cause than people expect.
Did WordPress core auto-update?
If the changed files are under /wp-admin/, /wp-includes/, or are top-level files like wp-blog-header.php, check whether WordPress core auto-updated to a minor version (security release) overnight. WP Admin → Updates shows current core version; if it’s a recent timestamp, that’s your cause.
Did you (or someone on your team) deploy code?
Custom themes, mu-plugins, and your own plugins won’t typically be auto-updated. But if you (or a developer / agency working on the site) ran a deploy, did a git pull on the server, or edited theme files in the WP admin theme editor, those files will show up as changed. Check your git log / deploy log / theme-editor history.
Did a security plugin or migration plugin run?
Some plugins legitimately write files during normal operation: SiteVault during a backup or restore, ForgeCache during cache regeneration, page builders generating CSS files (Elementor’s elementor/css/, Divi’s et-cache/). These directories should generally be in the file-monitor skip list (added in 1.6.7+ via guardpress_file_monitor_skip_patterns), but custom setups can still surface them.
If the file-change timestamp in GuardPress → File Monitor matches the timestamp of a known event (Updates page entry, git deploy log, scheduled backup), you have your answer. If the timestamp doesn’t correlate with anything you can identify, that’s when investigation actually starts.
Step 2: Identify the File Category (Determines Your Options)
GuardPress assigns every flagged file to one of four categories. The category determines whether you can Restore inline, and from where:
1. WordPress core
Files under /wp-admin/, /wp-includes/, or top-level wp-*.php (e.g. wp-login.php, wp-config-sample.php).
Restore source
Available. Pulled from core.svn.wordpress.org at your installed WP version. Click the Restore button on the row in GuardPress → File Monitor.
2. WordPress.org-hosted plugin
Files under /wp-content/plugins/<slug>/ where <slug> matches a plugin on the WordPress.org Plugin Directory.
Restore source
Available. The latest plugin zip is downloaded from downloads.wordpress.org/plugin/<slug>.zip, the target file is extracted, and written in place. Note: this restores from the latest version on WP.org, not your currently-installed version — so if the changed file disappeared in a later plugin release, Restore will give you the newest version’s file (which may differ from what was there before).
3. WordPress.org-hosted theme
Files under /wp-content/themes/<slug>/ where <slug> matches a theme on the WordPress.org Theme Directory.
Restore source
Available. Same mechanism as plugins — latest theme zip from downloads.wordpress.org/theme/<slug>.zip.
4. Custom / non-WP.org files
Files in /wp-content/mu-plugins/, wp-config.php, drop-ins (object-cache.php, advanced-cache.php), themes not hosted on WP.org (your custom theme, a premium theme like Astra Pro, a child theme), plugins not on WP.org (your own custom plugins, Royal Plugins Pro tier, anything you built or bought directly).
Restore source
Not available inline. The Restore button is hidden for these because GuardPress has no canonical source to compare against (we deliberately don’t cache shadow copies — that’s what backup plugins are for). The row will show “No canonical source for this file — restore from a backup (SiteVault Pro) instead.”
For categories 1, 2, and 3 you have a one-click recovery path. For category 4 you need a backup.
Step 3: Take Action
If Restore is available (categories 1, 2, 3)
Open the File Monitor admin page
Go to GuardPress → File Monitor. Locate the row for the changed file.
Click the Restore button
GuardPress fetches the canonical file (core from core.svn.wordpress.org, plugin/theme from downloads.wordpress.org), writes it to the target path via WP_Filesystem, and writes a file_restore_attempt audit log entry at INFO severity. On success the row updates to show the new clean baseline.
Confirm the change in the audit log
GuardPress → Audit Log → filter for the most recent entries. You should see file_restore_attempt with the file path. If the restore failed (network error fetching the zip, file-system permission issue, etc.), the audit log entry shows the failure reason.
Test the affected functionality
If the restored file is in a plugin or theme that you actively use, exercise the affected feature to confirm everything still works after restore. WP.org always serves the canonical version — if your customisations were on top of that file, Restore will overwrite them.
If Restore is not available (category 4 — custom files)
The file has no canonical source GuardPress can fetch. Your options:
- Restore from a backup — if you’re running SiteVault Pro, open it and restore the affected file from a backup taken before the change. SiteVault stores per-file diffs so you can restore a single file without rolling back the whole site.
- If you (or your developer) made the change deliberately — nothing more to do. The new file content automatically becomes the new baseline on the next scheduled scan. No manual action is needed; the row simply stops appearing once the next scan establishes the new hash as the baseline.
- If you have no backup and don’t recognise the change — this is the hard scenario. Compare the file content against a known-good copy from your git repo, staging environment, or a previous deploy artifact. If the file looks malicious (PHP eval, base64-decoded payload, obfuscated code), run the Malware Scanner from GuardPress → Malware Scanner → Run Malware Scan Now and treat the site as compromised — see WordPress Malware Removal for the full cleanup path.
If wp-config.php shows as modified and you don’t remember changing it, investigate before restoring. The file legitimately changes when you (or WordPress) rotate authentication salts, change the table prefix, or add a constant. Restoring from an old backup may undo a security update you want to keep.
Recognising False Positives (Common Patterns)
These are file changes that look alarming but are almost always benign:
- Cache plugins regenerating CSS / JS — Elementor’s
wp-content/uploads/elementor/css/, Divi’swp-content/et-cache/, page-builder block CSS files. These regenerate on theme save, page edit, plugin update. Add these paths to the file-monitor skip list under GuardPress → Settings → Monitoring & Scanning if they’re noisy. - Backup plugin working directories —
wp-content/uploads/sitevault/,wp-content/updraft/,wp-content/backups*,wp-content/ai1wm-backups/. The file monitor in 1.6.7+ ships skip patterns for the most common backup plugin paths, but custom setups can still surface them. - Vendor / node_modules in custom plugins — if your developer ran
composer installornpm installon the server. The skip list coversvendor/,node_modules/,.git/, and.svn/by default. - SEO plugins regenerating sitemaps — some SEO plugins write a sitemap file to disk instead of generating it dynamically.
If You’re Getting Too Many File Integrity Emails
The emails are gated by deduplication state — pre-1.6.21 every daily scan re-emailed the same unresolved findings, and pre-1.6.24 the file monitor sent one email per changed file. Both bugs are fixed at 1.6.24+. If your inbox is being flooded, update GuardPress first. Full diagnosis flow at Quieting GuardPress Security Alert Email Flood.
Still Stuck? Email Priority Support
If you’ve worked through the triage flow and you’re not sure whether a file change is legitimate, or Restore is failing with an error, or you suspect a real compromise:
Email support@royalplugins.com with the diagnostic info below. Priority email support is included with your GuardPress Pro license — typical response time is within 24 hours, and we treat suspected-compromise tickets as highest priority.
Information to include in your email
- GuardPress version from WP Admin → Plugins (1.6.7+ ideally for the Restore feature, 1.6.24+ for clean email behaviour)
- WordPress version from WP Admin → Updates
- The full file path(s) flagged by the alert — e.g.
wp-content/plugins/example-plugin/includes/file.php - The change type — modified, deleted, or new
- The timestamp of the change from GuardPress → File Monitor
- What category the file is in — WP core / WP.org plugin / WP.org theme / custom / unknown
- Whether the Restore button appeared on the row, and if you clicked it, what audit-log entry was written
- What changed in the last 24 hours — updates, deploys, backups, content edits — anything that could correlate with the change timestamp
- If you suspect compromise: a one-line description of any other symptoms — unexpected admin users, traffic spikes, defaced pages, redirects, spam comments, etc.
If file changes are the start of a bigger investigation:
- WordPress Malware Removal — if the file change looks like a real compromise (PHP eval, base64 payloads, unknown admin users)
- Quieting Security Alert Email Flood — if file-monitor emails are arriving 100+ at a time or repeating daily
- File Integrity Monitor overview — the short feature description on the main GuardPress support page
- SiteVault Pro — one-click restore from per-file backups for custom files the canonical-source flow can’t reach