Closed jpmckinney closed 6 months ago
We should have an email sent when upgrading (even better if email is only sent for minor/major releases), as it has happened that a minor/major release broke the site.
Edit: Alternatively, we don't auto-upgrade for major, in which case Wordfence will send an email. We can use logic like at https://github.com/dependabot/fetch-metadata/blob/924483a3d758e3539d35e512c5ca92c75c7a748d/src/dependabot/update_metadata.ts#L77C17-L94 to find major upgrades.
Here's the bash script mentioned.
Instead, we use a must-use plugin, which would be equally difficult for an attacker to remove: https://ocdsdeploy.readthedocs.io/en/latest/develop/update/wordpress.html#wordpress
Regarding the issue description, logging in as admin requires: basic authentication to access wp-login.php; the admin user login; and multi-factor authentication. So, that's not a likely scenario.
#!/usr/bin/env bash
#
# Description: Updates wordpress site core and plugins
#
# Usage: $0 [siteid|all]
# Or in cron: @daily root $0
#
# Configuration: The following variables can be set in the site.config file(s)
# AUTOPATCH=yes # Enables this autopatching script for the site
#
# Notes: If you start getting 'Error: No plugins updated' from this script then it is probaly due to a premium plugin being used on the site
# Take a look at the code below to exclude the premium plugin from being automatically updated.
set -e
set -u
# Check we are root
if [ ${LOGNAME} != "root" ]; then
echo "ERROR: Execution of $0 stopped as not run by user root!"
exit 1
fi
# Default to running on all sites with the autopatch variable set to yes
USERINPUT=${1:-all}
# If user input is "all" we want to update all the sites we can.
if [[ ${USERINPUT} == "all" ]]; then
# find siteconfigs that need autopatching.
SITETODO=$(find /home/ -mindepth 2 -maxdepth 2 -path "/home/ez[0-9]*" -name "site.config" -type f -exec grep -il 'AUTOPATCH=yes' {} \; | grep -oP 'ez[0-9]+')
#Else we were passed a single site ID so check $1 is a vaild site
elif [ -f "/home/${USERINPUT}/site.config" ]; then
SITETODO=${USERINPUT}
else
echo "ERROR: File /home/${USERINPUT}/site.config does not exist"
echo "ERROR: Site does NOT exist. Patching not possible."
exit 3
fi
# Check and create the wp-cli cache
WP_CLI_CACHE=/home/wp-cli_cache
if ! [ -d "$WP_CLI_CACHE" ]; then
mkdir $WP_CLI_CACHE
chown admin:ezusers $WP_CLI_CACHE
chmod 2775 $WP_CLI_CACHE
fi
# Loop through the sites to do, and do them!
for SITE in ${SITETODO}; do
# Turning this into a big ol' subshell so the site.config import is cleared down each loop.
(
#echo "Updating ${SITE}..."
source /home/${SITE}/site.config
# Double check the site is what we think it is
if [ "$SITE" != "$SITENAME" ]; then
echo "ERROR: $SITE is not an valid sitename"
exit 4
fi
#Used so it we don't have to flag every command
WP_CLI="sudo -u ${SITENAME} -i WP_CLI_CACHE_DIR=$WP_CLI_CACHE -- wp-cli --quiet --path=/home/${SITENAME}/public_html --skip-plugins"
# Check everything is up to date
#echo " ...updating core..."
$WP_CLI core update
#echo " ...updating themes..."
$WP_CLI theme update --all
#echo " ...updating plugins..."
$WP_CLI plugin update --all --exclude=updraftplus,elementor-pro,form-vibes,jetpack,child-theme-configurator # premium plugins that causes an error https://github.com/wp-cli/wp-cli/issues/5320
#echo " ...updating language..."
$WP_CLI core language update # This should be the last to be updated as plugins may have translation updates
)
done
WP can auto-update itself (/wp-admin/update-core.php) and plugins (/wp-admin/plugins.php).
That said, we can guarantee that these are updated by running a WP CLI script outside WordPress (e.g. to protect against an attacker gaining access to the WP admin and disabling updates – with the script, the attacker would need to be able to modify a readable, executable, but non-writable file owned by root and/or edit crontab).
Dogsbody shared a sample script in Slack.