r/ProWordPress • u/Used-Painter4245 • 2h ago
File integrity monitoring: how do you tell a host’s routine update from a planted backdoor in mu-plugins?
I maintain a WordPress security plugin and ran into a file-integrity case I’d like other people’s views on.
A client site on Hostinger flagged a change to wp-content/mu-plugins/hostinger-auto-updates.php. Hostinger had updated it themselves. Legitimate, but the alert kept showing up in every daily summary because the baseline only refreshed on upgrader_process_complete, and host-side changes never fire that.
The easy fix is to whitelist known host files by name. I didn’t want to: a backdoor can be called hostinger-anything.php, and mu-plugins is one of the first places attackers persist because it loads without activation. Per-host exceptions also don’t scale.
What I went with instead is a general rule. A change is treated as routine only when both of these are true:
- The file’s
Version:header went up compared to the baseline - The changed file passes the malware signature scan
php
$old = $baseline[ $path ]['version'] ?? '';
$new = get_file_data( $abs, [ 'v' => 'Version' ] )['v'] ?? '';
$routine = $old !== '' && $new !== ''
&& version_compare( $new, $old, '>' )
&& ! $scanner->scan_file( $abs ); // no findings
Routine changes are accepted into the baseline and logged quietly. Anything else is still an alert: no header, same or lower version, any scanner hit, or files like wp-config.php that never have a header. There’s also a manual “these changes are expected” button to re-baseline.
The weak spots I know of:
- An attacker who knows the rule can bump the header
- Signature scanning misses novel code
- Files without headers always alert, which is noisy for some hosts
How do you handle this? Do you compare against vendor checksums where they exist (core has them, hosts mostly don’t)? Diff size heuristics? Just accept the noise and train clients to ignore it? Curious what’s worked on agency fleets.