With package signatures you can ensure that the code you’re running is signed by the vendors you trust. The concept involves two fundamental items:
- a secret signing key that is known only to the vendor, and
- it’s matching public key that you mark as trusted.
Using the underlying math of the public-key cryptography, you’re able confirm that the ZIP files downloaded by your WordPress instance were signed by the vendors you trust. The same core principle is used by software updates to your phone, car and potentially fridge.

The Hardest Thing
Is to show trust without relying on a single authority.
With app stores on phones everything is controlled by a single company who implant a specific public key in your device which then makes it trust all other keys derived from it (used by individual app developers).
Most Linux distributions rely on a similar hard-coded list of trusted public keys. All software available from their official package repository is signed by the matching private keys. That’s why using a package from outside the official repository (such as Node.js) requires importing the authors custom public key.
With the distributed future of the WordPress core, plugin and theme distribution, the challenge is to build a user interface for managing the trusted keys that is easy to use and feels reliable.
Support in WordPress Core
The first version of package signature verification was added in WordPress 5.2 after long discussions in the feature proposal ticket. It is implemented as part of the download_url()
function and intended only for verifying WP core updates:
- When downloading the package ZIP, it checks if the hostname of the URL belongs to a list of hostnames
wp_signature_hosts
with signature verification enabled. - If yes, then it attempts to extract the package signature from the HTTP response header
X-Content-Signature
or download it from the same URL but with the.sig
suffix. - If the signature is found, it is then checked against the list of known public keys
wp_trusted_keys
. - If the signature is missing or the verification fails, it returns a “soft-fail” error but proceeds to use the downloaded ZIP unless the
wp_signature_softfail
filter is set to returnfalse
.
Cryptographic Components
The actual cryptography is based on the following two standards:
- SHA384 file hashes, and
- Ed25519 private-public key pairs.
Having the decision to use these two primitives allows us to focus on the implementation and usability of the solution instead of arguing over cryptographic alternatives and their potential benefits.
Proposal for Distributed Package Signing
Below is a detailed proposal for how this could be implemented across multiple distributed package vendors:

Risks and Concerns
The following scenarios have to be considered when designing and building this system:
- The vendor signing keys are compromised (made public) which allows anyone to create a package signed by a trusted key.
- The original vendor should be able to mark the key as invalid (revoked).
- The WP instances should stop trusting and using packages signed with revoked keys.
- The vendor wants to change their private key.
- The vendor should be able to publish and sign the new key. Old keys should be marked as invalid (revoked).
- Vendor looses access to the
UpdateURI
defined in their packages (expired domain). All update checks fail.- Users should be notified of the failed update checks in the WP admin or over email.
- Vendor packages must be kept isolated in their own namespace (directory prefix or suffix) to ensure another trusted vendor can’t publish and override the same package.
All of these issues are solved by a system where users are asked to curate the trusted keys and only a single key per vendor is supported at all times. This is the implementation in the Update Pilot client plugin.
Leave a Reply