WP-CLI’s plugin verify checksums is an awesome builtin security feature. With a single command wp plugin verify-checksums --all
you can make sure all of your WordPress.org plugins are valid and haven’t been tampered with. It’s one of the first commands I’ll reach to when malware is suspected. However many popular plugins are not on WordPress.org which means they are not included with the verify checks. Let’s explore how we might extend WP-CLI’s plugin verify-checksums
to cover all plugins, not just WordPress.org plugins.
Uncovering how the current checksums are generated
The source code that powers WordPress.org is open source. After a bit of digging I found the internal code that is responsible for generating the plugin checksums on WordPress.org. That code produces a checksums for every version of every plugin uploaded to WordPress.org. Here is an example of what a WooCommerce checksum file looks like.
Planning out plugin checksums for plugins not on WordPress.org
Ideally I’d just like to run the same wp plugin verify-checksums --all
command to check all plugins. There are couple problems. First, we’d need to build out own library of checksums or pull from a centralized 3rd party. And second, we’ll need to fallback to our own checks when a plugin is not found on WordPress.org. To do any of this we’d need to make changes to the existing WP-CLI command or create our own WP-CLI command.
Possible solutions for this have been discussed within WP-CLI here: https://github.com/wp-cli/ideas/issues/167. My first idea was to hook into it the when plugins are updated and generate local checksums. Considering anyone or any code can update plugins at anytime this method seems unlikely to be reliable. However maybe better then nothing? My next idea was to just build my own central repository of checksums. I figured I already own a bunch of paid WordPress plugins so I could probably source quite a few plugins myself. Also I might be able to extract checksums from CaptainCore, my WordPress management tool which is powering Anchor Hosting.
So begins WP Beacon, checksums for the WordPress community
The name WP Beacon comes from a few years back when I needed a place to fork a few plugins for PHP 8 compatibility. I always thought that name would be great for something security or health related in the WordPress space. So after a day stuck with the idea of extending plugins checksums I created a landing page for WP Beacon which I’m describing as checksums for the WordPress community.
After adapting the code which powers WordPress.org checksum creation I now have a WP-CLI command which can generate checksums for any locally installed WordPress plugin wp beacon plugin generate-checksums
. This is useful for generating checksums for an individual plugin or in bulk for many. For example the following script will generate checksums for most recent versions of ACF Pro.
versions=(6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 6.2.1.1 6.2.1 6.2.0)
license_key=MY_ACF_LICENSE_KEY
cd wp-content/plugins/
for version in ${versions[@]}; do
echo "Downloading ACF $version"
url="https://connect.advancedcustomfields.com/v2/plugins/download?p=pro&k=${license_key}&t=$version"
if [ -f "advanced-custom-fields-pro.zip" ]; then
rm advanced-custom-fields-pro.zip
fi
if [ -d "advanced-custom-fields-pro" ]; then
rm -rf advanced-custom-fields-pro/
fi
wget -q "$url" -O advanced-custom-fields-pro.zip
unzip -qq advanced-custom-fields-pro.zip
wp beacon plugin generate-checksums advanced-custom-fields-pro --disable-remote-check
done
All was going good until I discovered that many plugins have dirty releases which make checksums impractical
The whole idea of checksums is that for any released version of a plugin there is manifest that says these files should contain this content. This falls apart if you or the developer is making changes to files in between versions. So after some initial testing of wp beacon plugin verify-checksums --all
I discovered many plugins, not on WordPress.org, have dirty changes. An example of that comes from WPMU DEV Dashboard plugin where many files on the same version number had single line changed.
I’m sure that arbitrary line serves some purpose for WPMU DEV Dashboard however it exposes the reality with WordPress that many of us already know. With WordPress you the developer have the power to do anything you want. There is nothing in WordPress that says you can’t make file changes without updating the plugin version number. This limits the usefulness of checksums to only plugins that follow WordPress.org workflow, where a new version is required when files are changed.
Conclusion and alternative ideas
While my initial idea of solving WordPress plugins for the community might be a bit out of reach, this weekend project was not all for nothing. Here are my takeaways.
- WP Beacon is a great way to extend checksums for plugins not currently checked.
- A community sourced checksums might be possible for a selected plugins which follow strict version changes and/or can issue updated checksums when changes happen between releases.
- Checksums can only take you so far. Just because they fail doesn’t mean your plugins are comprised. Being able to see file level changes is far more valuable and should be coupled with checksums.
I think my next step will be to revisit a git based approach for tracking file level changes. That’s something I’m already doing here at Anchor Hosting and I think could be more valuable then simply verifying checksums.