{"id":224,"date":"2026-02-11T16:38:35","date_gmt":"2026-02-11T15:38:35","guid":{"rendered":"https:\/\/helloblog.io\/es\/vulnerabilidad-critica-wpvivid-backup-subida-arbitraria-archivos-cve-2026-1357\/"},"modified":"2026-02-11T16:38:35","modified_gmt":"2026-02-11T15:38:35","slug":"vulnerabilidad-critica-wpvivid-backup-subida-arbitraria-archivos-cve-2026-1357","status":"publish","type":"post","link":"https:\/\/helloblog.io\/es\/vulnerabilidad-critica-wpvivid-backup-subida-arbitraria-archivos-cve-2026-1357\/","title":{"rendered":"Vulnerabilidad cr\u00edtica en WPvivid Backup: subida arbitraria de archivos (CVE-2026-1357) y riesgo de RCE en sitios WordPress"},"content":{"rendered":"\n<p>Se ha publicado un aviso de seguridad importante sobre <strong>WPvivid Backup &#038; Migration<\/strong> (slug: <code>wpvivid-backuprestore<\/code>), un plugin de copias de seguridad\/migraci\u00f3n con <strong>m\u00e1s de 800.000 instalaciones activas<\/strong>. El problema es una <strong>subida arbitraria de archivos sin autenticaci\u00f3n<\/strong> que, en el peor escenario, permite <strong>Remote Code Execution (RCE)<\/strong> y puede desembocar en la toma completa del sitio.<\/p>\n\n\n\n<p>El matiz clave (y pr\u00e1ctico) es que el impacto cr\u00edtico se concentra en sitios donde se ha activado una funci\u00f3n concreta del plugin: <strong>permitir que otro sitio env\u00ede un backup al tuyo<\/strong> mediante una <strong>clave generada<\/strong> en los ajustes. Esta caracter\u00edstica viene <strong>desactivada por defecto<\/strong> y la <strong>caducidad de la clave<\/strong> solo puede configurarse hasta un <strong>m\u00e1ximo de 24 horas<\/strong>. Aun as\u00ed, si se ha usado alguna vez, conviene tratarlo como urgente.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Resumen de la vulnerabilidad (Wordfence Intelligence)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>Nombre\/entrada:<\/strong> \u201cMigration, Backup, Staging <= 0.9.123 - Unauthenticated Arbitrary File Upload\u201d<\/li>\n\n\n<li><strong>Severidad (CVSS):<\/strong> 9.8 (Critical)<\/li>\n\n\n<li><strong>CVE:<\/strong> CVE-2026-1357<\/li>\n\n\n<li><strong>Versiones afectadas:<\/strong> <= 0.9.123<\/li>\n\n\n<li><strong>Versi\u00f3n corregida:<\/strong> 0.9.124<\/li>\n\n\n<li><strong>Componente afectado:<\/strong> Migration, Backup, Staging &#8211; WPvivid Backup &#038; Migration<\/li>\n\n\n<li><strong>Vector destacado:<\/strong> <code>wpvivid_action=send_to_site<\/code><\/li>\n\n\n<li><strong>Bounty reportado:<\/strong> $2,145.00 (descubrimiento y reporte responsable por Lucas Montes (NiRoX) v\u00eda Bug Bounty Program)<\/li>\n\n<\/ul>\n\n\n\n<p>Seg\u00fan el an\u00e1lisis publicado, la vulnerabilidad combina dos problemas: <strong>manejo incorrecto de errores durante el descifrado RSA<\/strong> y <strong>ausencia de saneamiento de rutas (path sanitization)<\/strong> cuando se escriben archivos subidos. El resultado es que un atacante puede preparar una carga maliciosa, forzar la escritura del archivo fuera del directorio \u201cprotegido\u201d del backup y terminar colocando un <strong>PHP<\/strong> ejecutable en una ruta accesible p\u00fablicamente.<\/p>\n\n\n\n<div class=\"wp-block-group callout callout-warning is-style-warning is-layout-flow wp-block-group-is-layout-flow\" style=\"border-width:1px;border-radius:8px;padding-top:1rem;padding-right:1.5rem;padding-bottom:1rem;padding-left:1.5rem\">\n\n<h4 class=\"wp-block-heading callout-title\">\u00bfCu\u00e1ndo es cr\u00edtico de verdad?<\/h4>\n\n\n<p>El aviso recalca que afecta de forma cr\u00edtica a quienes tengan <strong>una clave generada<\/strong> en los ajustes del plugin para permitir la recepci\u00f3n de backups desde otro sitio. La funci\u00f3n est\u00e1 <strong>desactivada por defecto<\/strong> y la clave caduca como m\u00e1ximo en <strong>24 horas<\/strong>, pero si la has habilitado (aunque sea puntualmente), actualiza y revisa.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 permite el ataque: de subida de archivos a ejecuci\u00f3n remota de c\u00f3digo<\/h2>\n\n\n\n<p>Una <strong>arbitrary file upload<\/strong> (subida arbitraria de archivos) en WordPress es especialmente peligrosa porque no se limita a \u201csubir un fichero\u201d: si el atacante consigue escribir un <code>.php<\/code> en una carpeta servida por el servidor web, puede ejecutar ese c\u00f3digo v\u00eda HTTP y ganar control (por ejemplo, desplegando una <strong>webshell<\/strong>, que es un script para ejecutar comandos y gestionar archivos desde el navegador).<\/p>\n\n\n\n<p>En este caso, el flujo vulnerable est\u00e1 ligado a la caracter\u00edstica de WPvivid para <strong>recibir backups entrantes<\/strong> desde otra instalaci\u00f3n. El endpoint\/acci\u00f3n mencionada en el informe (<code>wpvivid_action=send_to_site<\/code>) es la puerta de entrada que un actor malicioso intentar\u00eda explotar.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">An\u00e1lisis t\u00e9cnico: d\u00f3nde falla el proceso de cifrado\/descifrado<\/h2>\n\n\n\n<p>El plugin gestiona la recepci\u00f3n del backup en la funci\u00f3n <code>send_to_site()<\/code> de la clase <code>WPvivid_Send_to_site<\/code>. Ah\u00ed carga la l\u00f3gica criptogr\u00e1fica y utiliza una clave generada en la configuraci\u00f3n (guardada en opciones) para descifrar el contenido recibido.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>public function send_to_site()\n{\n    include_once WPVIVID_PLUGIN_DIR . '\/includes\/class-wpvivid-crypt.php';\n    $test_log = new WPvivid_Log();\n    $test_log-&gt;CreateLogFile('test_backup','no_folder','transfer');\n    $test_log-&gt;WriteLog('test upload.','notice');\n\n    try\n    {\n        if (isset($_POST['wpvivid_content']))\n        {\n            global $wpvivid_plugin;\n            $wpvivid_plugin-&gt;wpvivid_log = new WPvivid_Log();\n\n            $default = array();\n            $option = get_option('wpvivid_api_token', $default);\n            if (empty($option))\n            {\n                die();\n            }\n            if ($option['expires'] != 0 &amp;&amp; $option['expires'] &lt; time())\n            {\n                die();\n            }\n\n            $crypt = new WPvivid_crypt(base64_decode($option['private_key']));\n            $body  = base64_decode($_POST['wpvivid_content']);\n            $data  = $crypt-&gt;decrypt_message($body);\n        }\n    }\n    catch (Exception $e)\n    {\n        \/\/ ...\n    }\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#F97583\">public<\/span><span style=\"color:#F97583\"> function<\/span><span style=\"color:#B392F0\"> send_to_site<\/span><span style=\"color:#E1E4E8\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    include_once<\/span><span style=\"color:#79B8FF\"> WPVIVID_PLUGIN_DIR<\/span><span style=\"color:#F97583\"> .<\/span><span style=\"color:#9ECBFF\"> '\/includes\/class-wpvivid-crypt.php'<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $test_log <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#F97583\"> new<\/span><span style=\"color:#79B8FF\"> WPvivid_Log<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $test_log<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">CreateLogFile<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">'test_backup'<\/span><span style=\"color:#E1E4E8\">,<\/span><span style=\"color:#9ECBFF\">'no_folder'<\/span><span style=\"color:#E1E4E8\">,<\/span><span style=\"color:#9ECBFF\">'transfer'<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $test_log<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">WriteLog<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">'test upload.'<\/span><span style=\"color:#E1E4E8\">,<\/span><span style=\"color:#9ECBFF\">'notice'<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    try<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">        if<\/span><span style=\"color:#E1E4E8\"> (<\/span><span style=\"color:#79B8FF\">isset<\/span><span style=\"color:#E1E4E8\">($_POST[<\/span><span style=\"color:#9ECBFF\">'wpvivid_content'<\/span><span style=\"color:#E1E4E8\">]))<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">            global<\/span><span style=\"color:#E1E4E8\"> $wpvivid_plugin;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            $wpvivid_plugin<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#E1E4E8\">wpvivid_log <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#F97583\"> new<\/span><span style=\"color:#79B8FF\"> WPvivid_Log<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            $default <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> array<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            $option <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#B392F0\"> get_option<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">'wpvivid_api_token'<\/span><span style=\"color:#E1E4E8\">, $default);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">            if<\/span><span style=\"color:#E1E4E8\"> (<\/span><span style=\"color:#79B8FF\">empty<\/span><span style=\"color:#E1E4E8\">($option))<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">                die<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">            if<\/span><span style=\"color:#E1E4E8\"> ($option[<\/span><span style=\"color:#9ECBFF\">'expires'<\/span><span style=\"color:#E1E4E8\">] <\/span><span style=\"color:#F97583\">!=<\/span><span style=\"color:#79B8FF\"> 0<\/span><span style=\"color:#F97583\"> &#x26;&#x26;<\/span><span style=\"color:#E1E4E8\"> $option[<\/span><span style=\"color:#9ECBFF\">'expires'<\/span><span style=\"color:#E1E4E8\">] <\/span><span style=\"color:#F97583\">&#x3C;<\/span><span style=\"color:#79B8FF\"> time<\/span><span style=\"color:#E1E4E8\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">                die<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            $crypt <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#F97583\"> new<\/span><span style=\"color:#79B8FF\"> WPvivid_crypt<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">base64_decode<\/span><span style=\"color:#E1E4E8\">($option[<\/span><span style=\"color:#9ECBFF\">'private_key'<\/span><span style=\"color:#E1E4E8\">]));<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            $body  <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> base64_decode<\/span><span style=\"color:#E1E4E8\">($_POST[<\/span><span style=\"color:#9ECBFF\">'wpvivid_content'<\/span><span style=\"color:#E1E4E8\">]);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">            $data  <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> $crypt<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">decrypt_message<\/span><span style=\"color:#E1E4E8\">($body);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    catch<\/span><span style=\"color:#E1E4E8\"> (<\/span><span style=\"color:#79B8FF\">Exception<\/span><span style=\"color:#E1E4E8\"> $e)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#6A737D\">        \/\/ ...<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>La parte interesante (y peligrosa) est\u00e1 en <code>decrypt_message()<\/code>. El plugin descifra un \u201csession key\u201d con RSA y luego usa ese valor como clave para inicializar el cifrado sim\u00e9trico (Rijndael\/AES v\u00eda <code>phpseclib<\/code>). El informe describe un comportamiento problem\u00e1tico: si el descifrado RSA falla, se obtiene <code>false<\/code>, pero el c\u00f3digo <strong>no corta la ejecuci\u00f3n<\/strong> y pasa ese <code>false<\/code> al inicializador del cifrado sim\u00e9trico.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>public function decrypt_message($message)\n{\n    $len = substr($message, 0, 3);\n    $len = hexdec($len);\n    $key = substr($message, 3, $len);\n\n    $cipherlen = substr($message, ($len + 3), 16);\n    $cipherlen = hexdec($cipherlen);\n\n    $data = substr($message, ($len + 19), $cipherlen);\n\n    $rsa = new Crypt_RSA();\n    $rsa-&gt;loadKey($this-&gt;public_key);\n    $key = $rsa-&gt;decrypt($key);\n\n    $rij = new Crypt_Rijndael();\n    $rij-&gt;setKey($key);\n    return $rij-&gt;decrypt($data);\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#F97583\">public<\/span><span style=\"color:#F97583\"> function<\/span><span style=\"color:#B392F0\"> decrypt_message<\/span><span style=\"color:#E1E4E8\">($message)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $len <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, <\/span><span style=\"color:#79B8FF\">0<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#79B8FF\">3<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $len <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> hexdec<\/span><span style=\"color:#E1E4E8\">($len);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $key <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, <\/span><span style=\"color:#79B8FF\">3<\/span><span style=\"color:#E1E4E8\">, $len);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $cipherlen <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, ($len <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#79B8FF\"> 3<\/span><span style=\"color:#E1E4E8\">), <\/span><span style=\"color:#79B8FF\">16<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $cipherlen <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> hexdec<\/span><span style=\"color:#E1E4E8\">($cipherlen);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $data <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, ($len <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#79B8FF\"> 19<\/span><span style=\"color:#E1E4E8\">), $cipherlen);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rsa <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#F97583\"> new<\/span><span style=\"color:#79B8FF\"> Crypt_RSA<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rsa<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">loadKey<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">$this<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#E1E4E8\">public_key);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $key <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> $rsa<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">decrypt<\/span><span style=\"color:#E1E4E8\">($key);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rij <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#F97583\"> new<\/span><span style=\"color:#79B8FF\"> Crypt_Rijndael<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rij<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">setKey<\/span><span style=\"color:#E1E4E8\">($key);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    return<\/span><span style=\"color:#E1E4E8\"> $rij<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">decrypt<\/span><span style=\"color:#E1E4E8\">($data);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>La consecuencia que describe Wordfence es sutil: al pasar <code>false<\/code> a la librer\u00eda, esta lo interpreta como una cadena de <strong>bytes nulos<\/strong> (null bytes). Eso vuelve la \u201cclave\u201d <strong>predecible<\/strong>, permitiendo que un atacante cifre una carga maliciosa con esa clave de bytes nulos y el plugin la \u201cdescifre\u201d como v\u00e1lida.<\/p>\n\n\n\n<p>A esto se le suma un segundo problema: el nombre de archivo que llega desde el payload descifrado se acepta <strong>sin saneamiento de ruta<\/strong>, lo que permite <strong>directory traversal<\/strong> (por ejemplo, escapar del directorio de backups). En un escenario real, eso facilita escribir archivos en directorios p\u00fablicos y, si el atacante sube un <code>.php<\/code>, activar la <strong>RCE<\/strong> simplemente accediendo a ese fichero.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 corrigi\u00f3 el parche (0.9.124)<\/h2>\n\n\n\n<p>El proveedor public\u00f3 la correcci\u00f3n en <strong>WPvivid Backup 0.9.124<\/strong>. La soluci\u00f3n aborda ambos frentes: valida el resultado del descifrado y a\u00f1ade controles para limitar el tipo de archivo que se acepta en la recepci\u00f3n.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1) Corte temprano si el descifrado RSA devuelve una clave inv\u00e1lida<\/h3>\n\n\n\n<p>La correcci\u00f3n a\u00f1ade una comprobaci\u00f3n expl\u00edcita en <code>decrypt_message()<\/code> para evitar que <code>false<\/code> o una clave vac\u00eda termine inicializando el cifrado sim\u00e9trico.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>public function decrypt_message($message)\n{\n    $len = substr($message, 0, 3);\n    $len = hexdec($len);\n    $key = substr($message, 3, $len);\n\n    $cipherlen = substr($message, ($len + 3), 16);\n    $cipherlen = hexdec($cipherlen);\n\n    $data = substr($message, ($len + 19), $cipherlen);\n\n    $rsa = new Crypt_RSA();\n    $rsa-&gt;loadKey($this-&gt;public_key);\n    $key = $rsa-&gt;decrypt($key);\n\n    if ($key === false || empty($key))\n    {\n        return false;\n    }\n\n    $rij = new Crypt_Rijndael();\n    $rij-&gt;setKey($key);\n    return $rij-&gt;decrypt($data);\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#F97583\">public<\/span><span style=\"color:#F97583\"> function<\/span><span style=\"color:#B392F0\"> decrypt_message<\/span><span style=\"color:#E1E4E8\">($message)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $len <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, <\/span><span style=\"color:#79B8FF\">0<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#79B8FF\">3<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $len <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> hexdec<\/span><span style=\"color:#E1E4E8\">($len);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $key <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, <\/span><span style=\"color:#79B8FF\">3<\/span><span style=\"color:#E1E4E8\">, $len);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $cipherlen <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, ($len <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#79B8FF\"> 3<\/span><span style=\"color:#E1E4E8\">), <\/span><span style=\"color:#79B8FF\">16<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $cipherlen <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> hexdec<\/span><span style=\"color:#E1E4E8\">($cipherlen);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $data <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> substr<\/span><span style=\"color:#E1E4E8\">($message, ($len <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#79B8FF\"> 19<\/span><span style=\"color:#E1E4E8\">), $cipherlen);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rsa <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#F97583\"> new<\/span><span style=\"color:#79B8FF\"> Crypt_RSA<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rsa<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">loadKey<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">$this<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#E1E4E8\">public_key);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $key <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> $rsa<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">decrypt<\/span><span style=\"color:#E1E4E8\">($key);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    if<\/span><span style=\"color:#E1E4E8\"> ($key <\/span><span style=\"color:#F97583\">===<\/span><span style=\"color:#79B8FF\"> false<\/span><span style=\"color:#F97583\"> ||<\/span><span style=\"color:#79B8FF\"> empty<\/span><span style=\"color:#E1E4E8\">($key))<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">        return<\/span><span style=\"color:#79B8FF\"> false<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rij <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#F97583\"> new<\/span><span style=\"color:#79B8FF\"> Crypt_Rijndael<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $rij<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">setKey<\/span><span style=\"color:#E1E4E8\">($key);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    return<\/span><span style=\"color:#E1E4E8\"> $rij<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#B392F0\">decrypt<\/span><span style=\"color:#E1E4E8\">($data);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">2) Restricci\u00f3n de extensiones para aceptar solo ficheros t\u00edpicos de backup<\/h3>\n\n\n\n<p>Adem\u00e1s, se introduce una validaci\u00f3n del nombre de archivo y una lista blanca de extensiones permitidas para la funci\u00f3n de recepci\u00f3n. En el snippet del parche se ve una normalizaci\u00f3n del nombre (usando <code>basename()<\/code> y un <code>preg_replace<\/code>) y el control de extensiones permitidas: <code>zip<\/code>, <code>gz<\/code>, <code>tar<\/code>, <code>sql<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>$safe_name = basename($params['name']);\n$safe_name = preg_replace('\/[^a-zA-Z0-9._-]\/', '', $safe_name);\n$allowed_extensions = array('zip', 'gz', 'tar', 'sql');\n$file_ext = strtolower(pathinfo($safe_name, PATHINFO_EXTENSION));\n\nif (!in_array($file_ext, $allowed_extensions, true))\n{\n    $ret['result'] = WPVIVID_FAILED;\n    $ret['error']  = 'Invalid file type - only backup files allowed.';\n    echo wp_json_encode($ret);\n    die();\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#E1E4E8\">$safe_name <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> basename<\/span><span style=\"color:#E1E4E8\">($params[<\/span><span style=\"color:#9ECBFF\">'name'<\/span><span style=\"color:#E1E4E8\">]);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">$safe_name <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> preg_replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">'\/<\/span><span style=\"color:#DBEDFF\">[^a-zA-Z0-9._-]<\/span><span style=\"color:#9ECBFF\">\/'<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">''<\/span><span style=\"color:#E1E4E8\">, $safe_name);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">$allowed_extensions <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> array<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">'zip'<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">'gz'<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">'tar'<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">'sql'<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">$file_ext <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> strtolower<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">pathinfo<\/span><span style=\"color:#E1E4E8\">($safe_name, <\/span><span style=\"color:#79B8FF\">PATHINFO_EXTENSION<\/span><span style=\"color:#E1E4E8\">));<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">if<\/span><span style=\"color:#E1E4E8\"> (<\/span><span style=\"color:#F97583\">!<\/span><span style=\"color:#79B8FF\">in_array<\/span><span style=\"color:#E1E4E8\">($file_ext, $allowed_extensions, <\/span><span style=\"color:#79B8FF\">true<\/span><span style=\"color:#E1E4E8\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $ret[<\/span><span style=\"color:#9ECBFF\">'result'<\/span><span style=\"color:#E1E4E8\">] <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> WPVIVID_FAILED<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    $ret[<\/span><span style=\"color:#9ECBFF\">'error'<\/span><span style=\"color:#E1E4E8\">]  <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#9ECBFF\"> 'Invalid file type - only backup files allowed.'<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#79B8FF\">    echo<\/span><span style=\"color:#B392F0\"> wp_json_encode<\/span><span style=\"color:#E1E4E8\">($ret);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    die<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 sitios deber\u00edan considerarse en riesgo (checklist r\u00e1pida)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Tienes instalado <strong>WPvivid Backup &#038; Migration<\/strong> en una versi\u00f3n <strong><= 0.9.123<\/strong>.<\/li>\n\n\n<li>Has usado o habilitado la funcionalidad para <strong>recibir un backup desde otro sitio<\/strong> (clave generada en los ajustes del plugin).<\/li>\n\n\n<li>Aunque la clave sea temporal (m\u00e1ximo 24 horas), si el endpoint estuvo expuesto durante ese periodo, el riesgo existe.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Mitigaci\u00f3n y recomendaciones operativas<\/h2>\n\n\n\n<p>La acci\u00f3n principal es simple: <strong>actualizar WPvivid Backup a 0.9.124<\/strong> (versi\u00f3n corregida en el momento de la publicaci\u00f3n del aviso). Dada la naturaleza de una subida arbitraria con potencial de RCE, no es el tipo de fallo que convenga posponer.<\/p>\n\n\n\n<p>En paralelo, si en tu entorno se utiliza Wordfence, el aviso indica que <strong>Wordfence Premium<\/strong>, <strong>Wordfence Care<\/strong> y <strong>Wordfence Response<\/strong> recibieron una regla de firewall el <strong>22 de enero de 2026<\/strong> para bloquear intentos de explotaci\u00f3n. En <strong>Wordfence Free<\/strong>, esa misma protecci\u00f3n llegar\u00eda <strong>30 d\u00edas despu\u00e9s<\/strong>, el <strong>21 de febrero de 2026<\/strong>.<\/p>\n\n\n\n<div class=\"wp-block-group callout callout-info is-style-info is-layout-flow wp-block-group-is-layout-flow\" style=\"border-width:1px;border-radius:8px;padding-top:1rem;padding-right:1.5rem;padding-bottom:1rem;padding-left:1.5rem\">\n\n<h4 class=\"wp-block-heading callout-title\">Fechas clave del firewall de Wordfence (seg\u00fan el aviso)<\/h4>\n\n\n<p>Regla disponible para Premium\/Care\/Response: 22 de enero de 2026. Regla disponible para Wordfence Free: 21 de febrero de 2026.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Timeline de divulgaci\u00f3n (Disclosure Timeline)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>January 12, 2026<\/strong> &#8211; Se recibe el reporte de la vulnerabilidad de subida arbitraria en WPvivid Backup a trav\u00e9s del Bug Bounty Program de Wordfence.<\/li>\n\n\n<li><strong>January 22, 2026<\/strong> &#8211; Se valida el reporte y se confirma el exploit de prueba de concepto (PoC). Se contacta con el proveedor y se le invita a usar el <a href=\"https:\/\/www.wordfence.com\/threat-intel\/vendor\/vulnerability-management-portal\/\">Wordfence Vulnerability Management Portal<\/a>.<\/li>\n\n\n<li><strong>January 22, 2026<\/strong> &#8211; Usuarios de <a href=\"https:\/\/www.wordfence.com\/products\/wordfence-premium\/\">Wordfence Premium<\/a>, <a href=\"https:\/\/www.wordfence.com\/products\/wordfence-care\/\">Wordfence Care<\/a> y <a href=\"https:\/\/www.wordfence.com\/products\/wordfence-response\/\">Wordfence Response<\/a> reciben una regla de firewall para mitigar intentos de explotaci\u00f3n.<\/li>\n\n\n<li><strong>January 23, 2026<\/strong> &#8211; El proveedor responde y decide gestionar la divulgaci\u00f3n por email.<\/li>\n\n\n<li><strong>January 23, 2026<\/strong> &#8211; Se env\u00edan los detalles completos al proveedor; se confirma recepci\u00f3n y se inicia el trabajo de correcci\u00f3n.<\/li>\n\n\n<li><strong>January 28, 2026<\/strong> &#8211; Se publica la versi\u00f3n corregida del plugin: <strong>0.9.124<\/strong>.<\/li>\n\n\n<li><strong>February 21, 2026<\/strong> &#8211; Los usuarios de Wordfence Free recibir\u00e1n la misma protecci\u00f3n.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Cierre: qu\u00e9 hacer ahora mismo<\/h2>\n\n\n\n<p>El caso de WPvivid Backup es un recordatorio cl\u00e1sico de por qu\u00e9 las rutas de \u201cimportaci\u00f3n\/recepci\u00f3n\u201d (backups, migraciones, staging) son superficie de ataque prioritaria: si algo permite escribir archivos y el control falla, el salto a RCE suele estar cerca.<\/p>\n\n\n\n<p>Si gestionas sitios WordPress con este plugin, verifica versi\u00f3n y <strong>actualiza a 0.9.124<\/strong> cuanto antes, especialmente si has utilizado la opci\u00f3n de clave para recibir backups desde otro sitio. El fallo est\u00e1 catalogado como <strong>cr\u00edtico (CVSS 9.8)<\/strong> y el vector descrito permite ataques <strong>sin autenticaci\u00f3n<\/strong>.<\/p>\n\n\n<div class=\"references-section\">\n                <h2>Referencias \/ Fuentes<\/h2>\n                <ul class=\"references-list\"><li><a href=\"https:\/\/www.wordfence.com\/blog\/2026\/02\/800000-wordpress-sites-affected-by-arbitrary-file-upload-vulnerability-in-wpvivid-backup-wordpress-plugin\/\" target=\"_blank\" rel=\"noopener noreferrer\">800,000 WordPress Sites Affected by Arbitrary File Upload Vulnerability in WPvivid Backup WordPress Plugin<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/wpvivid-backuprestore\/migration-backup-staging-09123-unauthenticated-arbitrary-file-upload\" target=\"_blank\" rel=\"noopener noreferrer\">Migration, Backup, Staging &lt;= 0.9.123 &#8212; Unauthenticated Arbitrary File Upload<\/a><\/li><li><a href=\"https:\/\/www.cve.org\/CVERecord?id=CVE-2026-1357\" target=\"_blank\" rel=\"noopener noreferrer\">CVE-2026-1357<\/a><\/li><li><a href=\"https:\/\/wordpress.org\/plugins\/wpvivid-backuprestore\/\" target=\"_blank\" rel=\"noopener noreferrer\">WPvivid Backup &amp; Migration \u2013 plugin (WordPress.org)<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/bug-bounty-program\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Bug Bounty Program<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vendor\/vulnerability-management-portal\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Vulnerability Management Portal<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/products\/wordfence-premium\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Premium<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/products\/wordfence-care\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Care<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/products\/wordfence-response\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Response<\/a><\/li><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>WPvivid Backup (m\u00e1s de 800.000 instalaciones activas) ha corregido un fallo cr\u00edtico que permite a atacantes sin autenticar subir archivos arbitrarios y llegar a ejecuci\u00f3n remota de c\u00f3digo. Si tienes habilitada la funci\u00f3n de \u201crecibir backups\u201d con una clave generada, toca revisar y actualizar ya.<\/p>\n","protected":false},"author":15,"featured_media":223,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[112,12,113,11,10],"class_list":["post-224","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-seguridad","tag-cve","tag-plugins","tag-rce","tag-seguridad","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/posts\/224","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/comments?post=224"}],"version-history":[{"count":0,"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/posts\/224\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/media\/223"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/media?parent=224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/categories?post=224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/es\/wp-json\/wp\/v2\/tags?post=224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}