Updates and Ed25519 signature verification
MM CRA Toolkit updates come from mmplugs.com over the standard WordPress update channel. Every package is cryptographically signed with Ed25519 and verified by the toolkit against a bundled public key before WordPress installs it.
How it works
A daily cron event (mmcra_daily_update_check) calls the mmplugs.com /update endpoint with your license key, instance ID, slug, and current version. The server compares the version, and if a newer release is available, returns:
- New version number
- Download URL (a signed, short-lived URL — not a permanent file path)
- SHA-256 hash of the package bytes
- Ed25519 signature over the package bytes
- Tested-up-to and required-PHP metadata
- Markdown changelog for the WordPress update modal
WordPress then handles the update display in the Plugins screen. When you click Update, the toolkit:
- Downloads the package
- Verifies the byte-length is plausible (under 8 MB)
- Re-hashes the bytes and compares against the SHA-256 from the metadata
- Verifies the Ed25519 signature against the public key compiled into the plugin
- If any check fails, refuses the install with a specific error code
Failure modes
| Error code | Meaning | |—|—| | mmcra_unsigned | Server returned the update without signature/hash. Refusing to install (fail closed). | | mmcra_bad_pubkey | The public key constant in the plugin is malformed. Reinstall the plugin. | | mmcra_bad_signature | The signature header is malformed. Network corruption or hostile server. | | mmcra_sha_mismatch | Downloaded bytes don't match the hash the server reported. Hostile MITM or corrupted CDN cache. | | mmcra_sig_invalid | Signature doesn't validate against the public key. Tampered package — do not install. | | mmcra_package_size | Package size implausible. Out-of-band malformed response. | | mmcra_no_sodium | PHP sodium extension missing. Host needs to enable it (default on PHP 7.4+, very rare to be missing). |
Any of these block the install. The error appears in the WP admin update flow. Fix the underlying issue and try again — never bypass.
Why this matters
If mmplugs.com is ever compromised and an attacker serves a tampered package, every install in the field refuses to apply it. The attacker would need both the binary AND the signing key, and the signing key never leaves our update server.
This is the standard "supply chain integrity" pattern (Sigstore, npm provenance, Debian package signing). The Cyber Resilience Act's Annex I implicitly requires it for any "product with digital elements."
Manual update
If you'd rather update manually, you can:
- Download the latest zip from /account/.
- Deactivate and delete the old plugin (your settings, audit log, and artifacts are preserved — they live in the database and uploads dir).
- Upload the new zip via Plugins → Add New → Upload Plugin.
You miss the signature verification doing it this way. The download from mmplugs.com is HTTPS, which guards against network MITM, but doesn't guard against a server-side compromise the way the in-band signature check does. Use the auto-update channel when you can.
Disable auto-updates
If you want to control update cadence yourself:
// In wp-config.php or a mu-plugin
add_filter( 'auto_update_plugin', function( $update, $item ) {
if ( isset( $item->slug ) && $item->slug === 'mm-cra-toolkit' ) {
return false;
}
return $update;
}, 10, 2 );
This stops automatic background updates. The "Update available" badge still appears in the Plugins screen — you click it when you're ready.
Update gating
If your license has expired and grace has run out, the /update endpoint returns a stub response with no download URL. WordPress sees no update available. Re-activating the license restores the update channel — no version is missed because the server tracks state per-license, not per-call.