{"id":221,"date":"2026-02-11T16:39:25","date_gmt":"2026-02-11T15:39:25","guid":{"rendered":"https:\/\/helloblog.io\/da\/kritisk-filupload-sarbarhed-wpvivid-backup-cve-2026-1357\/"},"modified":"2026-02-11T16:39:25","modified_gmt":"2026-02-11T15:39:25","slug":"kritisk-filupload-sarbarhed-wpvivid-backup-cve-2026-1357","status":"publish","type":"post","link":"https:\/\/helloblog.io\/da\/kritisk-filupload-sarbarhed-wpvivid-backup-cve-2026-1357\/","title":{"rendered":"Kritisk filupload-s\u00e5rbarhed i WPvivid Backup rammer op til 800.000 WordPress-sites (CVE-2026-1357)"},"content":{"rendered":"\n<p>Hvis du k\u00f8rer WPvivid Backup &#038; Migration (plugin-sluget <strong>wpvivid-backuprestore<\/strong>), er der kommet en alvorlig advisory, som er v\u00e6rd at tage helt bogstaveligt: en <strong>unauthenticated arbitrary file upload<\/strong> kan bruges til at f\u00e5 <strong>remote code execution (RCE)<\/strong> og i praksis fuld overtagelse af et WordPress-site. Pluginet har over <strong>800.000 aktive installationer<\/strong>, s\u00e5 blast radius er stor &#8211; men det er vigtigt at forst\u00e5 den konkrete foruds\u00e6tning for, om din installation er kritisk eksponeret.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hvad er problemet \u2013 og hvem er faktisk ramt?<\/h2>\n\n\n\n<p>S\u00e5rbarheden er registreret som <strong>CVE-2026-1357<\/strong> med <strong>CVSS 9.8 (Critical)<\/strong> og g\u00e6lder <strong>WPvivid Backup<\/strong> i versioner <strong><= 0.9.123<\/strong>. Den er rettet i <strong>0.9.124<\/strong>.<\/p>\n\n\n\n<p>Det helt centrale (og ofte oversete) nuancepunkt: If\u00f8lge advisoryen er s\u00e5rbarheden kun <em>kritisk<\/em> for sites, hvor du i pluginets indstillinger har <strong>genereret en n\u00f8gle<\/strong>, som bruges til at lade et andet site sende en backup <em>til<\/em> dit site (\u201dreceive backup from another site\u201d). Funktionen er <strong>sl\u00e5et fra som standard<\/strong>, og n\u00f8glens udl\u00f8b kan kun s\u00e6ttes til <strong>maksimalt 24 timer<\/strong>.<\/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\">Konsekvens i praksis<\/h4>\n\n\n<p>Hvis foruds\u00e6tningerne er opfyldt, kan en angriber uden login uploade vilk\u00e5rlige filer (fx en PHP webshell) til et webtilg\u00e6ngeligt sted og derefter eksekvere koden &#8211; typisk ender det i komplet kompromittering.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Kort s\u00e5rbarhedsresume (Wordfence Intelligence)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Advisory: <em>Migration, Backup, Staging <= 0.9.123 - Unauthenticated Arbitrary File Upload<\/em><\/li>\n\n\n<li>CVE: <strong>CVE-2026-1357<\/strong><\/li>\n\n\n<li>CVSS: <strong>9.8 (Critical)<\/strong><\/li>\n\n\n<li>P\u00e5virkede versioner: <strong><= 0.9.123<\/strong><\/li>\n\n\n<li>Rettet version: <strong>0.9.124<\/strong><\/li>\n\n\n<li>Bounty (rapporteret via bug bounty): <strong>$2,145.00<\/strong><\/li>\n\n\n<li>Angrebsvektor: parameteren <strong>wpvivid_action=send_to_site<\/strong><\/li>\n\n\n<li>\u00c5rsager: fejl i RSA-dekryptering\/h\u00e5ndtering + manglende path-sanitization ved filskrivning, hvilket muligg\u00f8r directory traversal og upload af fx PHP-filer<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Teknisk gennemgang: hvorfor kan det blive til RCE?<\/h2>\n\n\n\n<p>WPvivid har en funktion til at modtage en backup fra et andet site ved hj\u00e6lp af en kortlivet, genereret n\u00f8gle. I koden h\u00e5ndteres modtagelsen via metoden <code>send_to_site()<\/code> i klassen <code>WPvivid_Send_to_site<\/code>.<\/p>\n\n\n\n<p>Flowet er (forenklet) s\u00e5dan her: Pluginet tjekker, at der findes en konfiguration (<code>wpvivid_api_token<\/code>) og at den ikke er udl\u00f8bet. Derefter oprettes en <code>WPvivid_crypt<\/code>-instans og et POST-felt (<code>wpvivid_content<\/code>) base64-dekodes og dekrypteres.<\/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>\/\/ Uddrag af flowet, som advisoryen beskriver\n$option = get_option('wpvivid_api_token', array());\nif (empty($option)) {\n    die();\n}\nif ($option['expires'] != 0 &amp;&amp; $option['expires'] &lt; time()) {\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<\/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:#6A737D\">\/\/ Uddrag af flowet, som advisoryen beskriver<\/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\">, <\/span><span style=\"color:#79B8FF\">array<\/span><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\">empty<\/span><span style=\"color:#E1E4E8\">($option)) {<\/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:#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><\/code><\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">1) RSA-dekryptering fejler \u2013 men eksekveringen stopper ikke korrekt<\/h3>\n\n\n\n<p>Kernen i s\u00e5rbarheden ligger i <code>decrypt_message($message)<\/code>. Her fors\u00f8ger pluginet at RSA-dekryptere en session key. Hvis dekrypteringen fejler, ender <code>$key<\/code> som <code>false<\/code>. Advisoryen beskriver, at pluginet i den s\u00e5rbare version ikke terminerer korrekt i den situation, men i stedet sender v\u00e6rdien videre til AES\/Rijndael-initialiseringen.<\/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>\/\/ S\u00e5rbart m\u00f8nster (konceptuelt):\n$key = $rsa-&gt;decrypt($key);\n\n$rij = new Crypt_Rijndael();\n$rij-&gt;setKey($key);   \/\/ $key kan v\u00e6re false\nreturn $rij-&gt;decrypt($data);\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:#6A737D\">\/\/ S\u00e5rbart m\u00f8nster (konceptuelt):<\/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 style=\"color:#6A737D\">\/\/ $key kan v\u00e6re false<\/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><\/code><\/pre><\/div>\n\n\n\n<p>Det kritiske er, hvordan den underliggende crypto-library (phpseclib) h\u00e5ndterer den type input: <code>false<\/code> bliver behandlet som en streng af <strong>null bytes<\/strong>. Det g\u00f8r n\u00f8glen forudsigelig, og s\u00e5 kan en angriber selv konstruere en \u201cgyldigt\u201d krypteret payload ved at bruge en kendt null-byte key.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2) Filnavne accepteres uden sanitization \u2192 directory traversal ud af backup-mappen<\/h3>\n\n\n\n<p>Advisoryen fremh\u00e6ver ogs\u00e5 et separat (men afg\u00f8rende) problem: Filnavne fra den dekrypterede payload bliver accepteret uden tilstr\u00e6kkelig sanitization, s\u00e5 en angriber kan lave <strong>directory traversal<\/strong> og dermed slippe ud af den tilt\u00e6nkte (beskyttede) backup-mappe. Resultatet er, at man kan f\u00e5 en fil skrevet i en webtilg\u00e6ngelig mappe.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3) Ingen type-\/extension-checks \u2192 upload af vilk\u00e5rlige filer (fx PHP)<\/h3>\n\n\n\n<p>N\u00e5r du kombinerer (1) forudsigelig n\u00f8gle ved fejlet dekryptering med (2) directory traversal og (3) frav\u00e6r af filtype-\/extension-kontrol, f\u00e5r du den klassiske k\u00e6de: <strong>uploade en vilk\u00e5rlig PHP-fil<\/strong> og derefter ramme den via HTTP for at trigge <strong>RCE<\/strong>.<\/p>\n\n\n\n<div class=\"wp-block-group callout callout-danger is-style-danger 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\">Hvorfor arbitrary file upload n\u00e6sten altid er \u201cgame over\u201d<\/h4>\n\n\n<p>N\u00e5r en angriber kan skrive en fil, de selv kontrollerer, i en mappe der kan tilg\u00e5s fra webserveren, er n\u00e6ste skridt typisk en webshell, persistence og fuld overtagelse. Det er grunden til, at CVSS lander p\u00e5 9.8.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">S\u00e5dan blev det rettet i 0.9.124<\/h2>\n\n\n\n<p>Patchen best\u00e5r af to konkrete forbedringer, som matcher de to svageste punkter:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>Der er tilf\u00f8jet et check i <code>decrypt_message()<\/code> der stopper og returnerer <code>false<\/code>, hvis <code>$key === false<\/code> eller <code>$key<\/code> er tom. Det lukker den forudsigelige null-byte key-situation ved fejlet RSA-dekryptering.<\/li>\n\n\n<li>Der er tilf\u00f8jet en <strong>file extension check<\/strong> i <code>send_to_site()<\/code> samt sanitization af filnavnet, s\u00e5 upload kun accepterer backup-typer. I patch-eksemplet er de tilladte endelser: <strong>zip<\/strong>, <strong>gz<\/strong>, <strong>tar<\/strong>, <strong>sql<\/strong>. Hvis endelsen ikke matcher, returneres en fejl (\u201dInvalid file type &#8211; only backup files allowed.\u201d) og requesten termineres.<\/li>\n\n<\/ol>\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>\/\/ Patch-id\u00e9en i decrypt_message():\n$key = $rsa-&gt;decrypt($key);\nif ($key === false || empty($key)) {\n    return false;\n}\n\n$rij = new Crypt_Rijndael();\n$rij-&gt;setKey($key);\nreturn $rij-&gt;decrypt($data);\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:#6A737D\">\/\/ Patch-id\u00e9en i decrypt_message():<\/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 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:#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><\/code><\/pre><\/div>\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>\/\/ Patch-id\u00e9en i send_to_site():\n$safe_name = basename($params['name']);\n$safe_name = preg_replace('\/[^a-zA-Z0-9._-]\/', '', $safe_name);\n\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    $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:#6A737D\">\/\/ Patch-id\u00e9en i send_to_site():<\/span><\/span>\n<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>\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\">    $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\">Wordfence: beskyttelse via firewall-regel (tidslinje)<\/h2>\n\n\n\n<p>Wordfence oplyser, at deres brugere fik en firewall-regel mod exploit-fors\u00f8g p\u00e5 f\u00f8lgende tidspunkt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>Wordfence Premium<\/strong>, <strong>Wordfence Care<\/strong> og <strong>Wordfence Response<\/strong>: firewall-regel udsendt <strong>22. januar 2026<\/strong>.<\/li>\n\n\n<li><strong>Wordfence Free<\/strong>: samme beskyttelse rulles ud <strong>30 dage senere<\/strong>, dvs. <strong>21. februar 2026<\/strong> (if\u00f8lge advisoryen).<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Disclosure timeline (som rapporteret)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>January 12, 2026<\/strong> &#8211; S\u00e5rbarheden blev indsendt via Wordfence Bug Bounty Program.<\/li>\n\n\n<li><strong>January 22, 2026<\/strong> &#8211; Rapporten blev valideret og proof-of-concept bekr\u00e6ftet. Wordfence kontaktede leverand\u00f8ren og inviterede til at bruge Wordfence Vulnerability Management Portal.<\/li>\n\n\n<li><strong>January 22, 2026<\/strong> &#8211; Firewall-regel blev udsendt til Wordfence Premium\/Care\/Response.<\/li>\n\n\n<li><strong>January 23, 2026<\/strong> &#8211; Leverand\u00f8ren svarede og valgte e-mail som kanal.<\/li>\n\n\n<li><strong>January 23, 2026<\/strong> &#8211; Fuld disclosure blev sendt til leverand\u00f8ren, som bekr\u00e6ftede og gik i gang med fix.<\/li>\n\n\n<li><strong>January 28, 2026<\/strong> &#8211; WPvivid Backup <strong>0.9.124<\/strong> blev frigivet med patch.<\/li>\n\n\n<li><strong>February 21, 2026<\/strong> &#8211; Wordfence Free f\u00e5r firewall-beskyttelsen.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Hvad b\u00f8r du g\u00f8re p\u00e5 et WordPress-site i drift?<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>Tjek om WPvivid Backup &#038; Migration er installeret (slug: <strong>wpvivid-backuprestore<\/strong>).<\/li>\n\n\n<li>Hvis du k\u00f8rer <strong>0.9.123 eller \u00e6ldre<\/strong>, opdat\u00e9r til <strong>0.9.124<\/strong> hurtigst muligt.<\/li>\n\n\n<li>Vurd\u00e9r om funktionen til at modtage backups fra et andet site er i brug: Har du genereret en key i plugin-indstillingerne? Hvis ja, er det scenariet, advisoryen beskriver som kritisk eksponeret.<\/li>\n\n\n<li>Hvis du bruger Wordfence: v\u00e6r opm\u00e6rksom p\u00e5, at firewall-reglen afh\u00e6nger af produkt (Premium\/Care\/Response vs Free) og udrulningsdatoerne n\u00e6vnt ovenfor.<\/li>\n\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Konklusion<\/h2>\n\n\n\n<p>CVE-2026-1357 i WPvivid Backup er et skoleeksempel p\u00e5, hvordan sm\u00e5 fejl i fejlh\u00e5ndtering i kryptografi (RSA-dekryptering der ikke afbryder korrekt) kan blive til en praktisk udnyttelig k\u00e6de, n\u00e5r det kombineres med manglende path-sanitization og frav\u00e6r af filtypekontrol. Den er rettet i <strong>0.9.124<\/strong>, og hvis du har aktiveret \u201csend backup to this site\u201d-scenariet med en genereret n\u00f8gle, b\u00f8r du behandle opdateringen som akut.<\/p>\n\n\n<div class=\"references-section\">\n                <h2>Referencer \/ Kilder<\/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 (WordPress.org plugin)<\/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><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>En kritisk unauthenticated arbitrary file upload i WPvivid Backup kan i v\u00e6rste fald give remote code execution. Her er, hvem der reelt er udsat, hvad fejlen skyldes, og hvad du skal opdatere til.<\/p>\n","protected":false},"author":64,"featured_media":220,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[111,12,11,13,10],"class_list":["post-221","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sikkerhed","tag-cve","tag-plugins","tag-sikkerhed","tag-wordfence","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/posts\/221","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/users\/64"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/comments?post=221"}],"version-history":[{"count":0,"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/posts\/221\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/media\/220"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/media?parent=221"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/categories?post=221"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/da\/wp-json\/wp\/v2\/tags?post=221"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}