Get Started
Security April 20, 2026 6 min read

Decryption Failure, Full Takeover: Inside the WPvivid Backup RCE (CVE-2026-1357)

A missing return-value check in WPvivid Backup and Migration turned a failed RSA decryption into an unauthenticated remote code execution path affecting over 900,000 WordPress sites.

Backup plugins sit in a uniquely sensitive position on a WordPress site. They have reasons to receive large uploads, they write files to disk, and they frequently include endpoints designed to accept data from other sites – a “push” from a staging environment, a migration from an old host, an incremental sync from a parent site. That design surface is exactly where CVE-2026-1357, a CVSS 9.8 unauthenticated remote code execution flaw in WPvivid Backup & Migration, found its foothold. With more than 900,000 active installations, the plugin is one of the most broadly deployed backup tools in the ecosystem, and every site running version 0.9.123 or earlier was reachable by an attacker with nothing more than an internet connection.

A Cryptographic Handshake That Failed Open

WPvivid’s site-to-site transfer feature – used when a user chooses to push a backup from one installation to another – relies on a hybrid encryption handshake. The sending site encrypts a symmetric AES session key using the receiving site’s RSA public key, and the receiving site decrypts that session key with its private key before using it to decrypt the payload that follows. On paper this is a standard pattern. In WPvivid’s implementation, one small oversight turned the entire scheme into a bypass primitive.

The receiver calls openssl_private_decrypt() to unwrap the session key. When decryption fails – for example, when the attacker has never actually obtained the real public key and has simply submitted random bytes – this function returns false and leaves the destination buffer untouched. The vulnerable code did not check the return value. Execution continued, and the false value was passed directly into the phpseclib AES cipher as if it were a valid key.

How a Boolean Became a Predictable Encryption Key

phpseclib’s cipher routines coerce their inputs to strings. A PHP boolean false cast to a string is an empty string, which the library then pads or interprets as a key consisting entirely of null bytes. From that moment, the “encrypted” channel between attacker and server was no longer secret: both sides could derive the exact same all-zero key, because the attacker knew what would happen when decryption failed. Any payload the attacker encrypted with a null-byte AES key would be cleanly decrypted by the plugin using the same null-byte key, and the plugin would treat the result as an authenticated, trusted instruction from a peer site.

This is the kind of bug that looks innocuous in code review – a missing if ($key === false) return; – but collapses an entire trust boundary. The server believed it was talking to a site that held the matching RSA key. In reality, it was decrypting attacker-chosen plaintext with a key both sides could trivially compute.

From Broken Handshake to Arbitrary PHP on Disk

Bypassing the cryptographic check only gets an attacker into the plugin’s file-receiving routine. The second half of the vulnerability is what that routine did with the filenames it received. The transfer endpoint, reached through the wpvivid_action=send_to_site parameter, accepted a filename from the decrypted payload and wrote the incoming bytes to disk under the plugin’s upload directory. It did not normalize the path, did not reject ../ traversal sequences, and did not restrict the extension to known backup formats.

The practical consequence is that an unauthenticated attacker can submit a filename like ../../../../wp-content/uploads/shell.php along with arbitrary PHP source as the file body. The plugin writes the file. The web server serves it. The attacker now has remote code execution as the PHP user that runs WordPress, which is effectively the site. From there the attacker can read wp-config.php, extract database credentials, create administrator accounts, install persistent backdoors in legitimate theme or plugin files, or exfiltrate customer data.

Preconditions and Blast Radius

Sites are primarily at risk when the plugin’s “receive backup from another site” capability has been enabled at some point. That option generates a transfer key that remains valid for approximately 24 hours. However, because the cryptographic verification is the broken piece, an attacker does not need a legitimate key to exercise the file-upload path – they only need to reach the endpoint with the null-byte-encrypted payload. Any site that has the site-to-site transfer functionality reachable is a candidate.

The impact is especially severe for three common WPvivid use cases. Agencies running the plugin across client fleets are exposed on every site simultaneously; a single scanner can sweep an entire portfolio. Ecommerce sites using WPvivid for disaster recovery hold order history, customer PII, and payment metadata that an RCE exposes in full. And developers who left the migration feature enabled after a hand-off – a common oversight – are running a publicly reachable file upload on behalf of strangers.

The Irony of a Compromised Backup Tool

There is a particular bite to backup plugins being the entry point. These are the tools site owners install expecting a safety net. When the safety net is itself the vector, the attacker has not only a way in but also, in many cases, access to years of historical snapshots stored in nearby directories. Those backups often contain full database dumps, API keys committed to wp-config.php, and credentials for the very cloud providers the plugin was pushing data to. A successful exploit of CVE-2026-1357 is frequently not a single-site incident; it is a credential harvest that follows the attacker into Dropbox, Google Drive, Amazon S3, and wherever else offsite backups were being shipped.

Version 0.9.124 and What Site Owners Should Do

WPvivid’s maintainers released version 0.9.124 on January 28, 2026, with three specific changes: the plugin now checks the return value of openssl_private_decrypt() and aborts on failure, filenames from the decrypted payload are sanitized and resolved before any filesystem write occurs, and uploads are restricted to the expected backup file types (ZIP, GZ, TAR, SQL). The current release at the time of writing is 0.9.125, which layers additional fixes on top. Anything 0.9.123 or earlier is vulnerable and should be updated immediately.

Updating the plugin is the first step but not the only one. Because the vulnerability has had public proof-of-concept code since shortly after disclosure, any site that was running a vulnerable version for more than a few days should be audited as if it may have been reached. That means checking wp-content/uploads and the plugin’s backup directory for unexpected .php files, reviewing the administrator user list for accounts that were not created intentionally, rotating database credentials and any API keys stored in wp-config.php, and re-issuing tokens for every cloud storage provider the plugin was configured to use. If the site retained backup archives created before the patch, those should be treated as potentially tampered and rebuilt from a known-clean state rather than used for restore.

This is also the class of incident where a vulnerability scanner on the site itself is worth having. Trusti Security’s known vulnerability scanner checks every installed plugin and theme against a CVE database and flags matches, so a site still running WPvivid 0.9.123 would show up as a high-severity finding rather than sitting unnoticed until the next manual audit. The free tier offers on-demand scanning; the premium tier runs the check on a schedule as often as hourly and can send alerts to email, Slack, Telegram, or Pushover the moment a vulnerable version is detected. For the cleanup phase, the plugin’s core integrity check (premium) compares WordPress core files against official checksums, which is useful specifically because post-exploitation backdoors are frequently planted inside legitimate core files where file-listing audits miss them.

The Lesson Beyond This CVE

CVE-2026-1357 is a clean example of a pattern that keeps appearing in plugin advisories: the vulnerable code was not the file upload handler, and it was not obviously the crypto layer either. It was the glue between them – one unchecked return value that let a failed handshake silently succeed. Patching is straightforward; noticing that the patch is needed before an attacker does is the harder problem. Sites that treat plugin version monitoring as continuous rather than occasional are the ones that close windows like this in hours instead of months.

Related Articles