Sansec logo

PolyShell: unrestricted file upload in Magento and Adobe Commerce

Sansec

by Sansec Forensics Team

Published in Threat Research − March 17, 2026

PolyShell lets attackers upload executable files to any Magento or Adobe Commerce store via the REST API. Sansec has now observed attacks on 79.5% of all stores. No official patch exists for production versions. Many stores run web server configurations that enable remote code execution (RCE) or account takeover (stored XSS).

PolyShell: unrestricted file upload in Magento and Adobe Commerce

Sansec discovered and named the PolyShell vulnerability: a critical flaw in Magento's REST API that lets unauthenticated attackers upload executable files to any store. The attack uses a polyglot (code disguised as image) to bypass validation.

Versions affected by PolyShell

  • Unrestricted file upload — all Magento Open Source and Adobe Commerce versions up to 2.4.9-alpha2
  • Stored XSS — all versions pre-2.3.5 or custom webserver config
  • RCE via PHP upload — stock nginx 2.0.0–2.2.x (via index.php filename), any version with non-stock nginx passing all .php to fastcgi, Apache pre-2.3.5 without php_flag engine 0
  • Patched — 2.4.9-alpha3+ (pre-release only)

The vulnerable code has existed since the very first Magento 2 release. Adobe fixed it in the 2.4.9 pre-release branch as part of APSB25-94, but no isolated patch exists for current production versions. While Adobe provides a sample web server configuration that would largely limit the fallout, the majority of stores use a custom configuration from their hosting provider. Sansec investigated all known Magento and Adobe Commerce stores and found that many stores expose files in the upload directory.

Even when execution is blocked, the uploaded file stays on disk. A future configuration change, server migration, or web server swap could expose it.

How to protect against PolyShell

There is no official patch available for production Magento versions. Until Adobe releases one:

NB. Blocking web access to the upload directory (steps 2–3) does not prevent uploads. Attackers can still place malicious files on disk via the API. Only a WAF that blocks the API call itself (step 1) stops the attack.

  1. Block attacks in real-time. Deploy Sansec Shield to block PolyShell exploitation attempts.
  2. Restrict access to the upload directory. Verify that your web server blocks all access to pub/media/custom_options/. See the configuration examples below.
  3. Scan for compromise. Run eComscan to detect uploaded webshells, backdoors, and other malware.

Nginx: add this block inside your server configuration, before any \.php$ location block. Otherwise the PHP handler takes precedence and uploaded shells remain executable.

location ~* ^/pub/media/custom_options/ {
    deny all;
    return 403;
}

Apache: verify that pub/media/custom_options/.htaccess exists and contains:

<IfModule mod_php.c>
    php_flag engine 0
</IfModule>
Deny from all

If your Apache uses AccessFileName with a non-default name, rename the file accordingly.

PolyShell technical analysis

Magento's REST API accepts file uploads as part of the cart item custom options. When a product option has type "file", Magento processes an embedded file_info object containing base64-encoded file data, a MIME type, and a filename. The file is written to pub/media/custom_options/quote/ on the server.

Three critical checks are missing:

  1. No option ID validation. The submitted option ID is never verified against the product's actual options.
  2. No option type gating. The file upload logic triggers regardless of whether the product actually has a file-type option.
  3. No file extension restriction. Extensions like .php, .phtml, and .phar are not blocked. The only validation is an image header check (getimagesizefromstring), which is trivially bypassed.

The most dangerous endpoints are the anonymous guest cart routes, however these are not the only vulnerable ones.

MethodEndpointAuth
POST/V1/guest-carts/:cartId/itemsNone
PUT/V1/guest-carts/:cartId/items/:itemIdNone

The guest cart routes make this exploitable without any credentials.

GraphQL mutations use a different code path and are not vulnerable.

Live PolyShell attacks

Sansec Shield has blocked PolyShell exploitation attempts against 79.5% of all protected Magento stores since March 16th. The first probing started on March 16 at 12:00 UTC and automated mass scanning kicked in on March 19th. Since March 23, Sansec has recorded more than 50 IPs probing for PolyShell attacks.

Source IPs observed in PolyShell scanning (50+)
3.12.250[.]83
3.88.149[.]41
3.150.234[.]247
18.220.50[.]153
23.22.254[.]35
31.134.0[.]53
31.134.1[.]34
31.134.7[.]117
31.134.11[.]173
31.134.15[.]89
31.134.15[.]251
45.136.24[.]213
45.136.26[.]181
45.136.27[.]218
45.147.233[.]211
45.147.234[.]73
45.155.166[.]228
52.24.6[.]119
64.49.38[.]96
78.129.161[.]63
79.130.2[.]23
81.169.144[.]135
91.132.124[.]183
103.216.223[.]206
109.107.178[.]102
115.79.194[.]68
136.244.92[.]114
140.235.2[.]103
140.235.171[.]72
140.248.75[.]31
140.248.75[.]114
162.159.113[.]66
185.3.235[.]111
193.151.188[.]86
193.233.216[.]217
193.233.221[.]124
194.180.233[.]186
198.186.130[.]10
199.96.165[.]186
212.87.218[.]43
216.38.6[.]137
2001:19f0:6c01:15da:5400:6ff:fe05[:]e560

PolyShell payload analysis

Attackers upload polyglot files: valid GIF or PNG images that also contain executable PHP. Two distinct payload types are in active use.

PHP webshell with cookie authentication. The most common payload is a GIF89a polyglot dropped as index.php. It verifies the cookie d against a hardcoded MD5 hash and then accepts arbitrary code via eval(base64_decode()). The verification hash is a17028468cb2a870d460676d6d6da3ad63706778e3, derived from the cookie value. The shell also includes a file upload function triggered by $_POST["up"]:

PHP backdoor payload disguised as GIF image, using cookie-based authentication and eval to execute arbitrary code

Password-protected RCE shell. A second variant uses hash_equals() with the hardcoded MD5 hash 4009d3fa8132195a2dab4dfa3affc8d2 (double-MD5 of the password) and passes commands directly to system().

Filenames used in PolyShell attacks

Attackers are using a range of filenames to drop webshells. The most common pattern prepends the option ID to index.php (e.g. 780index.php). Other filenames observed in the wild:

index.php, json-shell.php, bypass.phtml, c.php, r.php, rce.php, static.php, test.php, blocked-json.php, bypass-async.php, urlencode-shell.php, xx_malicious_file.php, ato_poc.html, mikhail.html, accesson.php, toggige-arrow.jpg, adman.429.txt, adman.309.txt

Some attackers attempt Unicode obfuscation for the filename, such as \u0062\u0079\u0070\u0061\u0073\u0073.\u0070\u0068\u0070 (which decodes to bypass.php).

Post-exploitation: accesson.php backdoor

After gaining code execution through PolyShell, attackers deploy a secondary backdoor called accesson.php. Unlike the initial polyglot upload (which lands in pub/media/custom_options/), this backdoor is sprayed across multiple directories to maximize persistence. Sansec has observed accesson.php planted in all of these paths on a single compromised store:

var/assets/images/accesson.php
bamboo-specs/assets/images/accesson.php
lib/assets/images/accesson.php
app/assets/images/accesson.php
vendor/assets/images/accesson.php
pub/assets/images/accesson.php
bin/assets/images/accesson.php
setup/assets/images/accesson.php
generated/assets/images/accesson.php
phpserver/assets/images/accesson.php

The attackers create an assets/images/ subdirectory inside every top-level folder they can write to. Scattering copies ensures that at least one backdoor survives cleanup or redeployment.

The accesson.php backdoor is a variant of the cookie-authenticated webshell from the initial PolyShell payload, but without the GIF89a polyglot header.

The shell has three functions:

  1. Beacon. It always prints 8194460 (the result of 409723*20). Attackers use this as a fingerprint to locate live shells across thousands of compromised stores: a simple HTTP request reveals which paths are executable.
  2. Remote code execution. When the cookie d matches the hardcoded MD5 hash, the shell runs arbitrary PHP via eval(base64_decode($_REQUEST["id"])). This gives the attacker full control over the server.
  3. File upload. The up parameter copies an uploaded file to a path of the attacker's choice, enabling further malware deployment.

Post-exploitation: two-stage JavaScript persistence

After backdooring the server, attackers inject an obfuscated JavaScript loader into CMS pages or static blocks. The loader uses a two-stage persistence pattern: stage one replays a previously stored payload from localStorage, so the malware survives page reloads even if the external source goes down. Stage two fetches a fresh payload from lanhd6549tdhse[.]top and fingerprints the visitor using referrer, page title, and query parameters.

JavaScript skimmer payload that creates a script element with a base64-encoded source URL, exfiltrating the page referrer, title, and search parameters

This separation makes the attack resilient: blocking the external domain stops new payload delivery but does not neutralize payloads already cached in visitors' browsers.

If your store has been targeted by PolyShell, check for accesson.php files outside the usual upload directory and search your CMS content for references to lanhd6549tdhse[.]top, jslibrary[.]net, or canevaslab[.]com. A recursive search for the backdoor filename across the entire document root is the fastest way to find it:

find /var/www -name 'accesson.php' -type f

Is my Magento or Adobe Commerce store vulnerable to PolyShell?

Every production version of Magento Open Source and Adobe Commerce up to 2.4.8 is affected. Adobe fixed the underlying flaw in the 2.4.9 pre-release branch (alpha-3), but no isolated patch exists for current production releases. Even if your web server blocks PHP execution in the upload directory today, the uploaded files persist on disk and become dangerous if the server configuration changes.

How do I check if my store has been compromised?

Search for files uploaded through the vulnerability and for the accesson.php backdoor:

# Find all files in the custom options upload directory
find pub/media/custom_options/ -type f ! -name '.htaccess'

# Search for the accesson.php backdoor across the entire document root
find /var/www -name 'accesson.php' -type f

Any .php, .phtml, or .phar file in pub/media/custom_options/ is a strong indicator of compromise. Also check CMS pages and static blocks for references to lanhd6549tdhse[.]top, jslibrary[.]net, or canevaslab[.]com.

Is there an official Adobe patch for PolyShell?

No. As of March 2026, no official patch is available for production Magento or Adobe Commerce versions. The fix exists only in the 2.4.9 pre-release branch. Until Adobe ships a production patch, restrict access to the upload directory and deploy a WAF that blocks the vulnerable API endpoints. See How to protect against PolyShell above.

Timeline

DateEvent
2026-03-16Sansec adds PolyShell protection to Shield
2026-03-17Sansec adds detection patterns to eComscan
2026-03-17Sansec issues public warning
2026-03-19First PolyShell attacks observed in the wild
2026-03-23Mass scanning launched, 23% of protected stores targeted
2026-03-2456.7% of all stores have had malicious PHP code uploaded
2026-03-24PolyShell linked to WebRTC-based skimmer on $100B+ retailer
2026-03-30Mass attack wave: 79.5% of all stores targeted`
2026-03-30accesson.php backdoor and JS loaders deployed
2026-04-1482% of all stores hit with malicious uploads

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