WordPress 3.7 was released on October 24, 2013 and introduced an automatic update mechanism to ensure security fixes would be automatically deployed on all WordPress sites, in an effort to prevent recently-patched vulnerabilities from being massively exploited in the wild. This is widely regarded by security experts as a **good idea**. However, the WordPress automatic update feature had one glaring Achilles' heel: If a criminal or nation state were to hack into the WordPress update server, they could trigger a fake automatic update to infect WordPress sites with malware. This isn't just a theoretical concern, [it could have happened if not for WordFence's security researchers](https://www.wordfence.com/blog/2016/11/hacking-27-web-via-wordpress-auto-update/) finding and disclosing an easy attack vector into their infrastructure. WordPress 5.2 was released on May 7, 2019 and provides the first real layer of defense against a compromised update infrastructures: **offline digital signatures**. > Recommended reading: [What's a digital signature?](https://paragonie.com/blog/2015/08/you-wouldnt-base64-a-password-cryptography-decoded#digital-signatures) ## Signature Verification in WordPress 5.2 When your WordPress site installs an automatic update, from version 5.2 onwards, it will first check for the existence of an `x-content-signature` header. If one isn't provided by the update server, your WordPress site will instead query for a `filenamehere.sig` file. No matter how it's delivered, the signatures are calculated using [Ed25519](https://latacora.micro.blog/2018/04/03/cryptographic-right-answers.html#asymmetric-signatures) of the SHA384 hash of the file's contents. The signature is base64-encoded for safe transport. The signing keys used to release updates are managed by the WordPress.org core development team. The verification key for the initial release of WordPress 5.2 is `fRPyrxb/MvVLbdsYi+OOEv4xc+Eqpsj+kkAS6gNOkI0=` (expires April 1, 2021). (For the sake of specificity: Signing key here means **Ed25519 secret key**, while verification key means **Ed25519 public key**.) With the necessary information in hand, your WordPress site will then verify that the signature is valid. You can check this yourself, like so:
<?php
require_once "vendor/autoload.php"; // for Composer autoloaders, sodium_compat, etc.
function isWordPressUpdateValid(string $signature, string $filename): bool
{
$public_key = base64_decode('fRPyrxb/MvVLbdsYi+OOEv4xc+Eqpsj+kkAS6gNOkI0=');
$hash = hash_file('sha384', $filename, true);
return sodium_crypto_sign_verify_detached(base64_decode($signature), $hash, $public_key);
}
WordPress 5.2 users can just use the built-in `verify_file_signature()` function.
For the first release, WordPress will (by default) soft-fail if the signature is not valid. In future releases, the default will be configured to a hard failure. The reason for this unsafe default is to ensure updates aren't blocked if there's a bug in the update code (i.e. [arithmetic bugs with PHP 7.2.0-7.2.2, without ext/sodium, with PHP-FPM and opcache enabled](https://bugs.php.net/bug.php?id=75938)-- kind of a narrow corner-case, and hopefully the only one, but better safe than sorry).
If you're running a version of PHP older than 7.2, the Ed25519 signature verification is provided by [sodium_compat](https://github.com/paragonie/sodium_compat), a pure-PHP polyfill of libsodium developed by us.
To learn more about how we built sodium_compat, check out [Cryptographically Secure PHP Development](https://paragonie.com/blog/2017/02/cryptographically-secure-php-development).
### What All of This Means for WordPress Security
Before WordPress 5.2, if you wanted to infect every WordPress site on the Internet (approximately [33.8% of websites](https://w3techs.com/technologies/overview/content_management/all) as of this writing), you just had to hack their update server. Upon doing so, you can trick the automatic update feature into downloading and installing arbitrary code, which allows you to do all sorts of nefarious things (e.g. build the world's largest DDoS botnet).
After WordPress 5.2, you would need to pull off the same attack ***and*** somehow pilfer the signing key from the WordPress core development team.