Server-side file integrity monitoring is the layer of WordPress defense that doesn't depend on WordPress being trustworthy. A scheduled job running as root reads files independently, computes hashes, compares against a stored baseline, and alerts you through email (the OS mail utility, not wp_mail) when anything in the watched paths changes unexpectedly. Nothing inside WordPress can touch it: malware that compromises the WordPress user has no path to the root cron, the baseline file, or the outbound mail relay.
This is the only monitoring layer that survives the security plugins being silently disabled attack pattern, because the attacker who can disable Wordfence has no comparable ability to disable a system cron job running as a different user. This article covers three approaches at different sophistication levels: a 30-line custom cron script (sufficient for one or two sites), AIDE (the canonical Linux FIM, sufficient for one server), and OSSEC or Wazuh (full host intrusion detection, sufficient for multi-server deployments).
I started recommending server-side FIM seriously after a string of cleanups in 2019-2020 where attackers were targeting Wordfence's active_plugins row before deploying any visible payload. The site owners would check Wordfence ("looks fine"), the dashboard would say "Last scan: clean", and the actual compromise had been running for weeks. The fix isn't more in-WordPress monitoring; it's putting at least one monitoring layer outside the trust boundary the attacker has access to.
Why in-WordPress FIM isn't enough
Every WordPress security plugin that does file integrity monitoring (Wordfence's "Scan", Sucuri Security's integrity check, MalCare's site monitoring, WP Activity Log's file change detection) runs inside WordPress. The plugin computes hashes, stores a baseline, and reports differences. That works fine against opportunistic malware that doesn't know WordPress is monitored.
It fails against malware that knows. The same access that lets an attacker drop a backdoor in wp-content/uploads/ lets them:
- Remove the security plugin from
wp_options.active_plugins(the plugin stops running, no scans happen, no alerts). - Replace the plugin's baseline-storage file with a baseline that includes the backdoor (the scan runs but reports clean).
- Patch the plugin's check function via a
mu-pluginthat unregisters its hooks (the plugin appears active but does nothing). - Block the plugin's outbound notification request via a
pre_http_requestfilter (scans run, find the issue, but the alert never leaves the server).
Each of those is documented in Why Wordfence Got Silently Disabled. The pattern is real and reasonably common in 2020+ campaigns.
The structural fix: at least one monitoring layer has to live above the WordPress user's privilege, with state stored where WordPress can't reach it, and alerts delivered through a channel WordPress can't intercept. Three options in increasing sophistication:
Approach 1: A minimal custom cron script
The smallest possible useful FIM. A bash script run as root from a system crontab, hashing a fixed set of paths, comparing against a stored baseline, mailing on diff. ~50 lines total. Works on any Linux server with sha256sum, find, and mail.
Save as /usr/local/sbin/wp-fim.sh:
#!/usr/bin/env bash
# wp-fim.sh, server-side file integrity monitor for a single WordPress install.
# Source: https://techearl.com/wordpress-file-integrity-monitoring-server-side
# Site: https://techearl.com/
# Runs as root from cron. Stores baseline in /var/lib/wp-fim/ (out of WordPress's reach).
# Alerts via OS mail when anything in WATCH_PATHS changes from the baseline.
set -e
WP_ROOT="/var/www/wordpress"
ALERT_EMAIL="alerts@your-off-server-address.com"
HOSTNAME=$(hostname -f 2>/dev/null || hostname)
BASELINE_DIR="/var/lib/wp-fim"
mkdir -p "$BASELINE_DIR"
# Paths to monitor. wp-content/uploads/ is excluded because legitimate uploads
# change frequently; we monitor whether PHP appears there separately.
WATCH_PATHS=(
"$WP_ROOT/wp-config.php"
"$WP_ROOT/.htaccess"
"$WP_ROOT/index.php"
"$WP_ROOT/wp-admin"
"$WP_ROOT/wp-includes"
"$WP_ROOT/wp-content/plugins"
"$WP_ROOT/wp-content/themes"
"$WP_ROOT/wp-content/mu-plugins"
)
# 1. Compute the current state
CURRENT="$BASELINE_DIR/current.txt"
> "$CURRENT"
for p in "${WATCH_PATHS[@]}"; do
[ -e "$p" ] || continue
if [ -d "$p" ]; then
find "$p" -type f \( -name '*.php' -o -name '*.htaccess' -o -name '*.js' \) \
-exec sha256sum {} \; >> "$CURRENT" 2>/dev/null
else
sha256sum "$p" >> "$CURRENT" 2>/dev/null
fi
done
# 2. Also catch the "PHP appeared in uploads" case (always suspicious)
SUSPICIOUS_UPLOADS=$(find "$WP_ROOT/wp-content/uploads" -type f -name '*.php' 2>/dev/null)
# 3. Compare to baseline (first run creates the baseline)
BASELINE="$BASELINE_DIR/baseline.txt"
if [ ! -f "$BASELINE" ]; then
cp "$CURRENT" "$BASELINE"
echo "Initial baseline created at $BASELINE." | mail -s "wp-fim baseline created on $HOSTNAME" "$ALERT_EMAIL"
exit 0
fi
DIFF=$(diff "$BASELINE" "$CURRENT" || true)
if [ -n "$DIFF" ] || [ -n "$SUSPICIOUS_UPLOADS" ]; then
{
echo "WordPress file integrity anomaly on $HOSTNAME at $(date)."
echo
if [ -n "$SUSPICIOUS_UPLOADS" ]; then
echo "PHP files found in wp-content/uploads (always suspicious):"
echo "$SUSPICIOUS_UPLOADS"
echo
fi
if [ -n "$DIFF" ]; then
echo "Hash differences from baseline:"
echo "$DIFF" | head -200
fi
} | mail -s "ALERT: wp-fim integrity anomaly on $HOSTNAME" "$ALERT_EMAIL"
fiMake it executable and add to root's crontab:
sudo chmod 700 /usr/local/sbin/wp-fim.sh
sudo crontab -e
# Add:
*/15 * * * * /usr/local/sbin/wp-fim.sh > /var/log/wp-fim.log 2>&1That's it. Every 15 minutes the script runs as root, computes the current state, compares to the baseline stored in /var/lib/wp-fim/ (which the WordPress user cannot read or write because /var/lib/ is owned by root with mode 755), and emails on differences.
Updating the baseline after a legitimate change: deliberate. When you legitimately update a plugin, theme, or core, you run:
sudo /usr/local/sbin/wp-fim.sh # generates alert (the change you just made)
sudo cp /var/lib/wp-fim/current.txt /var/lib/wp-fim/baseline.txtThe discipline of having to consciously update the baseline is a feature. If you didn't make a change but the baseline differs, that's a real anomaly.
Why this beats in-WordPress FIM:
- Stored state is in
/var/lib/wp-fim/, not inwp-content/orwp_options. WordPress malware running aswww-datacannot read or write it. - Cron runs as root, scheduled by
/etc/crontab(which the WordPress user cannot read). - Alerts go through OS
mail, which reads/etc/aliases,/etc/postfix/, or similar. WordPress has no path to intercept. - The script itself is in
/usr/local/sbin/(root-owned, 700). WordPress can't modify it.
The only attack path is compromising the OS user (root) or finding an OS-level privilege escalation. Those are real but a vastly different (and rarer) threat model than "plugin CVE → admin user".
Approach 2: AIDE (canonical Linux FIM)
AIDE (Advanced Intrusion Detection Environment) is what real Linux deployments use. It's been the standard since 2001, ships in every major distro's package manager, and handles the things the custom script doesn't (proper baseline rotation, configuration as data, performance on large file trees, reasonable handling of legitimate noise).
Installation:
# Debian / Ubuntu
sudo apt install aide
# RHEL / Rocky / Alma
sudo dnf install aide
# Alpine
sudo apk add aideThe configuration is in /etc/aide/aide.conf (Debian-style) or /etc/aide.conf (RHEL-style). A WordPress-focused configuration adds these blocks:
# /etc/aide/aide.conf.d/50_aide_wordpress
# (Debian/Ubuntu drops files from this dir into the main aide.conf)
# Watch WordPress core deeply
/var/www/wordpress/wp-admin NORMAL
/var/www/wordpress/wp-includes NORMAL
/var/www/wordpress/wp-content/plugins NORMAL
/var/www/wordpress/wp-content/themes NORMAL
/var/www/wordpress/wp-content/mu-plugins NORMAL
# Watch the front-door files closely
/var/www/wordpress/wp-config.php R+sha256+sha512
/var/www/wordpress/.htaccess R+sha256+sha512
/var/www/wordpress/index.php R+sha256+sha512
# Watch for PHP appearing where it shouldn't
=/var/www/wordpress/wp-content/uploads/ Norm
!/var/www/wordpress/wp-content/uploads/.*\.(jpg|jpeg|png|gif|webp|svg|pdf|doc|docx|xls|xlsx|zip|mp4|mp3|m4a|webm|mov)$
# Ignore the cache directories that change constantly
!/var/www/wordpress/wp-content/cache
!/var/www/wordpress/wp-content/uploads/[0-9]{4}/[0-9]{2}/.*$ WLOG
Initialize the baseline:
sudo aideinit
# This takes a few minutes on a typical WordPress install.
# Output: /var/lib/aide/aide.db.new
# Move the new database into place as the active baseline
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.dbRun the check from cron:
sudo crontab -e
# Add:
0 4 * * * /usr/sbin/aide --check 2>&1 | mail -s "AIDE report $(hostname)" alerts@your-address.comAIDE outputs a structured report:
AIDE 0.18.6 found differences between database and filesystem!!
Summary:
Total number of entries: 12847
Added entries: 2
Removed entries: 0
Changed entries: 1
---------------------------------------------------
Added entries:
---------------------------------------------------
f++++++++++++++++: /var/www/wordpress/wp-content/uploads/2026/05/cache.php
f++++++++++++++++: /var/www/wordpress/wp-content/themes/active/test-cross-site.php
---------------------------------------------------
Changed entries:
---------------------------------------------------
f >.... mc.. : /var/www/wordpress/wp-config.php
f++++++++++++++++ marks new files (the two backdoors that appeared). f >.... mc.. marks a changed file (wp-config.php modification, with m = mtime changed, c = content/hash changed).
After a legitimate update, refresh the baseline:
sudo aide --update
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.dbWhy AIDE beats the custom script:
- Tuned hashing per file class (cheap SHA1 for many files, SHA256/SHA512 for security-critical ones)
- Built-in suppression for legitimate noise (cache directories, log rotation, atime changes)
- Configurable monitoring granularity (you don't need to hash an image file's content; size and mtime are enough)
- Reports are structured (machine-parseable) instead of free-form diffs
- Database integrity (AIDE signs its baseline, detecting tampering with the baseline itself)
For one or two WordPress sites on a single server, AIDE is the right tool.
Approach 3: Linux Malware Detect (maldet)
AIDE detects integrity changes. It doesn't know whether a changed file is malicious or just modified. maldet (Linux Malware Detect) is the complement: it actively scans files against signature databases for known web malware patterns, and flags hits regardless of whether they're new.
Maldet is particularly strong against PHP webshells (c99, r57, WSO, b374k, FilesMan) and the patterns the ClickFix family injects. It bundles its own signature feed plus a ClamAV integration for AV-style scanning.
Installation (it's not in distro repos; install from the maintainer's site):
cd /tmp
wget https://www.rfxn.com/downloads/maldetect-current.tar.gz
tar xzf maldetect-current.tar.gz
cd maldetect-*
sudo ./install.shConfiguration is in /usr/local/maldetect/conf.maldet. The key settings:
# Email alerts on detection
email_alert="1"
email_addr="alerts@your-off-server-address.com"
email_subj="maldet alert from %h"
# Run a daily scan from the included cron (already set up by install.sh)
# Set quarantine to ON so detections are auto-isolated
quarantine_hits="1"
quarantine_clean="0" # don't auto-clean; review before cleaning
# Watch this WordPress install
scan_max_depth="20"Manual scan:
sudo maldet -a /var/www/wordpressThe scan takes a few minutes for a typical WordPress install. Output:
Linux Malware Detect v1.6.5
(C) 2002-2023, R-fx Networks
(*) {SCAN ID: 240519-0431.123456}
(*) Scan time: Thu May 19 04:31:00 UTC 2026
(*) Scan results: 2 hits
{HEX}base64.inject.unclassed.6 : /var/www/wordpress/wp-content/uploads/2024/10/cache.php => quarantine
{MD5}backdoor.b374k.x86 : /var/www/wordpress/wp-content/themes/active/.cache.php => quarantine
The => quarantine action moves the file to /usr/local/maldetect/quarantine/ so it can't execute, then emails the alert. You review the quarantined files, confirm they're malicious, and delete them; or restore if it was a false positive.
maldet runs daily via the included cron. Combine it with AIDE: AIDE catches anything that changed, maldet catches anything malicious that's there whether it changed or not.
Approach 4: OSSEC or Wazuh (full HIDS, multi-host)
For deployments with multiple servers or where you want central alert management, OSSEC (the original) or Wazuh (the actively-developed fork) provide host-based intrusion detection that includes FIM, log analysis, rootkit detection, and active response.
The architecture: an agent on each monitored host reports to a central manager, which correlates events and sends consolidated alerts. The agent runs as a non-root user with carefully scoped permissions; the manager runs on a separate host.
This is enterprise-grade and over-engineered for one or two WordPress sites. It's the right answer when:
- You operate 5+ sites and want central visibility
- You have separate dev/staging/prod environments and want correlated alerts
- You need compliance-grade reporting (PCI DSS, HIPAA, SOC 2)
- You want to combine FIM with log analysis and active blocking in one platform
Installation and configuration is its own topic, well-covered in Wazuh's official documentation. For typical small-to-medium WordPress operations, this is more infrastructure than the value justifies. Approaches 1-3 are usually sufficient.
Picking the right approach for your site
A rough decision tree:
| Situation | Right approach |
|---|---|
| One WordPress site, shared hosting (no shell access) | You can't run this. Use Wordfence + manual periodic checks + plan to migrate to hosting with SSH |
| One WordPress site, VPS or managed hosting with SSH | The 30-line custom script (Approach 1) |
| Two to four sites on one VPS | AIDE (Approach 2) covering all sites |
| Five-plus sites on a VPS, or any site with paid plugins worth protecting | AIDE + maldet (Approaches 2 + 3) |
| Multiple servers, multiple environments, compliance requirements | OSSEC or Wazuh (Approach 4) |
The progression is additive: maldet doesn't replace AIDE; they complement each other. AIDE detects change, maldet detects malice. A baseline-matching file containing a c99 shell is malicious despite passing AIDE; a baseline-not-matching wp-config.php is suspicious despite passing maldet.
What to monitor (the list nobody else publishes completely)
The paths I always include in a WordPress server-side FIM configuration:
# WordPress core (any change is suspicious; updates should be the only source of changes)
/var/www/wordpress/wp-admin/
/var/www/wordpress/wp-includes/
/var/www/wordpress/index.php
/var/www/wordpress/wp-load.php
/var/www/wordpress/wp-settings.php
/var/www/wordpress/wp-login.php
/var/www/wordpress/wp-cron.php
# Configuration (change only when you legitimately edit config)
/var/www/wordpress/wp-config.php
/var/www/wordpress/.htaccess
# Plugins and themes (change only when you update or install)
/var/www/wordpress/wp-content/plugins/
/var/www/wordpress/wp-content/themes/
/var/www/wordpress/wp-content/mu-plugins/
# Drop-ins (should not exist unless you have specific caching/object-cache plugins)
/var/www/wordpress/wp-content/advanced-cache.php
/var/www/wordpress/wp-content/object-cache.php
/var/www/wordpress/wp-content/db.php
/var/www/wordpress/wp-content/sunrise.php
# Web server config (the broader attack surface)
/etc/apache2/ or /etc/nginx/
/etc/php/
# OS-level cron (where attackers schedule re-infection)
/etc/crontab
/etc/cron.d/
/etc/cron.daily/
/etc/cron.hourly/
/etc/cron.weekly/
/var/spool/cron/
# SSH access
/etc/ssh/sshd_config
/root/.ssh/authorized_keys
/home/*/.ssh/authorized_keys
# User-account shell hooks (the gsyndication-family persistence layer)
# Attackers append a base64 launcher to these files so a rogue process
# respawns the moment any shell session for the hosting user starts.
# See section 11 of /wordpress-malware-persistence-mechanisms.
/home/*/.bashrc
/home/*/.bash_profile
/home/*/.profile
/home/*/.zshrc
# User-home stash locations attackers use to hide resident binaries
/home/*/.config/htop/
The user-account shell hooks (.bashrc and friends) and the ~/.config/htop/ stash location deserve special note. They are the persistence layer behind the gsyndication.com wp-config.php reinjection pattern I see most often in 2026, and they fall completely outside the document root that WordPress security plugins ever scan. The malware itself lives above the WordPress directory, in the hosting user's home, where nothing scans by default. You can clean WordPress repeatedly while the malware is untouched one directory up.
This is the attack class known as above-doc-root persistence, and every popular WordPress security plugin is blind to it by design. Wordfence, Sucuri Security, iThemes Security Pro (Solid Security), Patchstack, MalCare, Jetpack Scan, and every hosting-provider one-click cleanup run as PHP inside the WordPress install and cannot enumerate processes, read user dotfiles, or look in /etc/. A server-side FIM with these paths in the watch list is the only monitoring layer that surfaces the reinfection source. Without it, the only signal you have that the attacker is still resident is wp-config.php repeatedly reinjecting itself with nothing in the WordPress filesystem looking suspicious, while every dashboard you log into tells you the site is clean. Section 11 of the persistence article covers the full attack class, the affected products list, and the modern campaigns in this category (Balada Injector, Sign1, gsyndication, Sysrv-hello, WP-VCD).
What NOT to monitor closely (too noisy):
/var/www/wordpress/wp-content/uploads/ # legitimate media uploads constantly
/var/www/wordpress/wp-content/cache/ # cache plugins write here on every request
/var/log/ # log rotation generates constant change
/tmp/ # by design
But monitor the wp-content/uploads/ directory for a specific case: any .php file appearing in it. PHP under uploads is always suspicious; image uploads are not. AIDE's = and ! syntax handles this distinction (see the example config above).
Alert delivery: the part most setups get wrong
The script or AIDE detected something. The alert has to reach you. Three layers to get right:
- Local mail transport: a working MTA on the server (
postfix,exim, ormsmtp) that can hand mail to a remote SMTP relay. Test withecho "test" | mail -s "test" you@example.com. - Outbound delivery: most hosting providers block port 25 outbound. Configure your MTA to use a transactional email provider (Postmark, SendGrid, Mailgun, Amazon SES) over port 587 with authentication.
- Off-server inbox: the alert email goes to an address you read. Not the same domain as the WordPress site. If the WordPress site is compromised, an attacker who can read mail at
alerts@thesite.comcan suppress alerts. Use a separate domain or a different mail provider entirely.
A working postfix-with-Sendgrid setup as relay (/etc/postfix/main.cf):
relayhost = [smtp.sendgrid.net]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
/etc/postfix/sasl_passwd:
[smtp.sendgrid.net]:587 apikey:YOUR-SENDGRID-API-KEY
After sudo postmap /etc/postfix/sasl_passwd and sudo systemctl restart postfix, mail flows.
Common mistakes
The patterns that make server-side FIM not actually work:
Storing the baseline inside the WordPress directory. Defeats the entire purpose. The baseline has to be at /var/lib/wp-fim/, /var/lib/aide/, or similar root-owned path that the WordPress user cannot read or write.
Running the FIM script as the WordPress user. Same problem. The script has to run as root (or at least as a user the WordPress user cannot become).
Letting the alert email arrive at an inbox on the same domain. If the WordPress site is compromised, the attacker controls the mail for the domain. Use an off-server inbox.
Not testing the alert delivery before relying on it. Send a deliberate test alert immediately after setup. If it doesn't arrive within a minute, the alert is broken and you'll discover it the next time you needed it.
Forgetting to update the baseline after legitimate changes. Then every legitimate plugin update generates a flood of "anomaly" alerts and you stop reading them. The discipline is: after every conscious legitimate change, refresh the baseline.
Monitoring wp-content/uploads/ for any change. Far too noisy; visitors and admins upload media constantly. Monitor it only for the specific case of PHP files appearing.
Skipping the OS-level paths. Attackers schedule re-infection via root cron, modify SSH config to add backdoor keys, and tweak web-server config to add auto_prepend_file directives. None of these are in the WordPress directory but all of them affect WordPress. Monitor them too.
Frequently asked questions
Wordfence's scan is a meaningful defense layer for most opportunistic attacks. It fails specifically against malware that knows WordPress is monitored and disables Wordfence before deploying the payload. Four mechanisms enable this disablement: editing the active_plugins option, deleting or renaming the plugin folder, swapping file permissions, or registering a mu-plugin that removes Wordfence's hooks at runtime. All four are reachable from a basic plugin CVE that gives the attacker file or database write access.
The structural fix is putting at least one FIM layer outside WordPress entirely, running with privileges the WordPress user does not have. Wordfence + server-side FIM together is stronger than either alone; Wordfence alone has the gap.
Usually no. AIDE needs root to install and to read OS-level paths (root's crontab, /etc/cron.d, /root/.ssh). On standard shared hosting you don't have root, and the hosting provider doesn't install AIDE for you. Some upper-tier managed WordPress hosts (WP Engine, Kinsta) run their own server-side scanning that's equivalent in effect, but you don't configure it directly.
For shared hosting without SSH or root, the realistic options are: (1) use the host's built-in security tools (varies by provider; ask), (2) supplement with Wordfence and accept the structural gap that it can be disabled, or (3) migrate to a VPS where you can run AIDE yourself. Option 3 is the right answer for any site with real traffic or paid plugins worth protecting.
Functionally similar: both compute file hashes, store a baseline, and report differences. The differences are licensing and tooling.
AIDE is open source under the GPL, free, in every major distro's package manager. It's the right answer for everyone who isn't required by a compliance framework to use commercial software.
Tripwire is split into Open Source Tripwire (also free, GPL, but no longer actively developed since around 2018) and Tripwire Enterprise (commercial, $1000s/host/year, with formal certifications, central reporting, and vendor support). Tripwire Enterprise is the right answer when compliance frameworks specifically require it (some PCI DSS audits, certain federal contracts), but for most WordPress deployments it's overkill.
For the custom script and AIDE both, 15-minute intervals are a reasonable default. Often enough that detection is near-realtime; rare enough that CPU and IO overhead is negligible. Hourly is fine if the server is busy or the install is large. Daily is too infrequent (an attacker has up to 24 hours of free run after compromise).
For maldet, the bundled cron runs daily. That's appropriate because signature scans are heavier than hash comparisons. Combine: AIDE every 15 minutes (cheap, catches change), maldet daily (heavier, catches known malicious patterns regardless of whether they changed).
Three steps. (1) Make the legitimate change (e.g., upgrade a plugin via WP-CLI). (2) Run a one-shot AIDE check and read it carefully to confirm the only changes are the ones you expected (plugin files modified, no surprise additions elsewhere). (3) If everything checks out, run sudo aide --update to generate a new database and sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db to make it the active baseline.
The deliberate review step in (2) is the part that matters. If you blindly accept every change, the FIM is decorative; an attacker who can time their compromise to overlap with one of your plugin updates rides through the update window without alert.
Only if they can escalate to root. AIDE's binary, configuration, baseline, and cron job all live in root-owned paths that the WordPress user cannot read or write. A typical WordPress compromise (plugin CVE, stolen credentials, file-upload exploit) gives the attacker access at the level of the WordPress user (commonly www-data or the cPanel account user). That access cannot reach AIDE.
An attacker who can reach AIDE has already escalated to root, which means they have full server control regardless of any application-layer monitoring. That's a different threat model than the standard WordPress compromise, and the defense is keeping the OS patched, requiring SSH key auth, and not running unnecessary privileged services.
Yes; they cover different attack stages. A WAF (Cloudflare, Wordfence's WAF, Sucuri Firewall) sits in front of the application and tries to block exploitation requests before they hit WordPress. FIM sits behind the application and detects when exploitation has already succeeded by noticing what changed.
WAF is prevention; FIM is detection. Even a well-tuned WAF lets some traffic through (the false-negative rate isn't zero), and zero-day plugin CVEs aren't in WAF rule sets until after the first wave. FIM catches the cases the WAF misses. Together they're significantly stronger than either alone.
See also
- How to Remove WordPress Malware: The Practitioner's Playbook: the broader cleanup methodology. FIM is the prevention; the playbook is what you do when FIM tells you the prevention failed.
- Why Wordfence (or Any Security Plugin) Keeps Getting Silently Disabled: the article this one is the structural fix for. If you've experienced the silent-disable pattern, server-side FIM is the response.
- Why WordPress Malware Keeps Coming Back: Persistence Mechanisms: the file-system and database locations that FIM monitoring needs to cover beyond the obvious WordPress paths.
- How to Find the Original Entry Point in a WordPress Compromise: the log forensics that pairs with FIM. FIM tells you something changed; log forensics tells you how the attacker got the access to change it.
- A Hardened wp-config.php Template: the configuration-side companion. FIM detects unauthorized changes to wp-config; hardening reduces what a successful change can accomplish.
- Off-Server WordPress Backups: 3-2-1 with Verification: the recovery layer that complements FIM. FIM tells you when a clean baseline ended; backups let you restore to before that point.
- Cross-Site Contamination on Shared WordPress Hosting: on multi-site shared hosting, FIM has to cover every site under the account, not just one.
- AI for WordPress Sysadmins: The Playbook: where file-integrity monitoring fits in the broader AI-assisted sysadmin workflow for WordPress infrastructure.
External references: the AIDE official documentation covers the configuration language in full. Linux Malware Detect's project page maintains the current signature feeds. Wazuh's documentation is the canonical reference for the OSSEC fork.
Sources
Authoritative references this article was fact-checked against.
- AIDE, Advanced Intrusion Detection Environment documentationaide.github.io
- Linux Malware Detect (maldet), project pagerfxn.com
- Wazuh, host intrusion detection documentationdocumentation.wazuh.com





