Repository navigation
Change alerts
Change alerts e-mails the alert recipients when something changes that attackers change after they get in: a new administrator, a new or activated plugin, a new theme, a must-use plugin or drop-in, an edited wp-config.php, or the settings for registration, the default role, the admin e-mail and the site address. Every change is also written to the activity log.
Changes made through WordPress to administrators and those settings are reported at once. Everything else is found by an hourly comparison with a stored baseline, which also catches changes made straight in the database or over FTP.
| Module ID | watch |
| Default | On |
| Available | Always |
| WP-CLI |
wp shouse watch (only while the module runs) |
| Since | 0.1.0 |
These are reported the moment WordPress makes the change:
- a user's role is set to Administrator: "User promoted to administrator". WordPress sets the role of a new account before it finishes creating it, so a new account created as Administrator is reported with this line too.
- the Administrator role is added to a user as an extra role: "Administrator role added to a user"
- a new account gets another role that can
manage_options, such as a custom role: "New administrator account" - one of the five watched settings changes:
users_can_register(anyone can register),default_role,admin_email,siteurl(WordPress address) orhome(site address)
Each alert names who did it: the logged-in user's login, or "no logged-in user (code, CLI or cron)". A new administrator is reported like this:
Subject: [SafeHouse] SITE NAME: new administrator
User promoted to administrator: jan (jan@example.com), by admin
If you did not expect this, lock the account and check the site.
A changed setting is reported like this:
Subject: [SafeHouse] SITE NAME: site setting changed
Setting default_role changed from "subscriber" to "administrator", by no logged-in user (code, CLI or cron)
Attackers change these settings to register their own administrator or take over password resets. If you did not expect this, change it back and check the site.
Values in alerts are cut to 200 characters. When admin_email changes, the old address gets the e-mail too, so the owner hears about it even if the attacker changed the address.
An immediate alert also updates the baseline, so the hourly check does not report the same change again.
Once an hour, SafeHouse takes an inventory and compares it with the baseline from the previous check:
| What | How it is compared | Reported as |
|---|---|---|
| Administrators | Users with the Administrator role, by login | "Administrator added: LOGIN", "Administrator removed: LOGIN" |
| Plugins | Names of the top-level entries in the plugins directory, so single-file plugins count too | "Plugin directory added: NAME", "Plugin directory removed: NAME" |
| Active plugins | The list of active plugins | "Plugin activated: FILE", "Plugin deactivated: FILE" |
| Themes | Names of the top-level entries in the themes directory | "Theme added: NAME", "Theme removed: NAME" |
| Must-use plugins | Names of the top-level entries in wp-content/mu-plugins
|
"Must-use plugin added: NAME", "Must-use plugin removed: NAME" |
| Drop-ins | Which of these files exist in wp-content: advanced-cache.php, object-cache.php, db.php, db-error.php, maintenance.php, install.php, sunrise.php, fatal-error-handler.php, php-error.php
|
"Drop-in added: FILE", "Drop-in removed: FILE" |
wp-config.php |
A SHA-256 hash of the file, in the WordPress folder or one level above it | "wp-config.php changed" |
| The five watched settings | Read straight from the options table, past any filter and the object cache | Setting NAME changed from "OLD" to "NEW" |
Directory entries whose names start with a dot, and index.php, are ignored. Reading the settings straight from the table means a value planted in the database is seen even when Hardening hides it from WordPress.
All changes from one check go out in one e-mail:
Subject: [SafeHouse] SITE NAME: changes detected
SafeHouse noticed these changes since the last check (up to an hour ago):
- Plugin directory added: example-plugin
- Plugin activated: example-plugin/example-plugin.php
- wp-config.php changed
If admin_email is among the changes, the old address gets this e-mail too.
Each check replaces the baseline with what it found, so every change is reported once. The first check after the module starts has nothing to compare with: it records the baseline and reports nothing.
The hourly check writes one inventory_changed entry with all changes. It is critical when any change is an administrator added, a must-use plugin added, a drop-in added, a wp-config.php change or a setting change, and a warning otherwise. Immediate alerts are logged as admin_added and option_changed, both critical.
Change alerts has no settings. While it runs, Details shows what it watches, for example "Watching 2 administrators, 14 plugins, 0 must-use plugins, 2 drop-ins, wp-config.php and 5 site settings." Before the first hourly check it shows "No baseline yet. It is recorded on the first hourly check."
Details also has two buttons:
| Button | What it does | Result |
|---|---|---|
| Check now | Runs the hourly check at once and e-mails what it finds. | "1 change found and reported.", "3 changes found and reported." or "No changes since the last check." |
| Accept current state | Stores the current inventory as the baseline without reporting anything. | "The current state is the new baseline." |
A deploy changes plugin directories and often wp-config.php. Without help, the next hourly check e-mails those changes as if an attacker made them. Accept the result of the deploy as the baseline instead.
At the end of a deploy script, run:
wp shouse watch acceptIt prints Success: Baseline updated. and writes inventory_accepted ("Current plugins, admins, files and site settings accepted as the baseline") to the activity log.
accept also takes in, without a report, anything else that changed since the last hourly check. To have those changes reported first, run a check before the deploy starts:
wp shouse watch checkcheck prints each change, e-mails them like the hourly check, and ends with Success: 2 change(s) reported. or Success: No changes.
A deploy script then looks like this:
wp shouse watch check
git pull --ff-only
wp shouse watch acceptWithout WP-CLI, select Accept current state in Details after the deploy.
The wp shouse watch command exists only while the module runs. On a site where Change alerts is off or SafeHouse is in safe mode, WP-CLI reports an unknown command, so guard the line in scripts that run on several sites. For more on deploys, see Deploy with git or CI.
- Option
shouse_watch_state(not autoloaded): the baseline, with administrator logins, directory listings, active plugins, drop-ins, thewp-config.phphash and the five settings. - Activity log entries:
admin_added,option_changed,inventory_changed,inventory_accepted.
- Switching the active theme is not watched. Only theme directories that appear or disappear are reported.
- File contents are not compared, except for
wp-config.php. A changed file inside an existing plugin or theme directory, inwp-content/uploads, or.htaccessis not reported. - The hourly check counts only users with the Administrator role. A user given a custom role or another role with administrator capabilities after the account was created is not reported.
- A change that is undone before the next hourly check, such as a plugin added and removed within the hour, is not seen.
- The hourly check runs on WP-Cron. If WP-Cron does not run, for example with
DISABLE_WP_CRONand no system cron job, only the immediate alerts, Check now andwp shouse watch checkwork. -
acceptand Accept current state take in any unreported change without a report. - Each change is e-mailed once. A change you missed in the e-mail stays in the activity log for 90 days.
- The e-mails are in English, whatever the site language.
These pages describe SafeHouse 0.2.0 and were last reviewed on 2026-10-07. · Repository · Releases · Changelog · Report a problem with these pages
Search every page and heading in the Pages box.
Start here
Modules
- All modules
- Security: Hardening · Login limits · Bot protection · Install lockdown
- Alerts: Change alerts · Plugin health · Vulnerability alerts
- Performance: LiteSpeed page cache · Cloudflare cache · Redis object cache
- WooCommerce: Omnibus price history
- Site tools: SMTP mail · Header and footer scripts · Duplicate posts and pages · Maintenance mode · Tweaks
Guides
- Behind Cloudflare or a proxy
- Running with Wordfence
- Configure in wp-config
- Deploy with git or CI
- Replacing other plugins
- Upgrade from WPHouse
Reference
Trust
Help