
PolyShell is an unauthenticated file-upload bug in Magento Open Source and Adobe Commerce 2.x. In March 2026, within days of disclosure, Sansec saw attacks on 56.7% of the stores it considered vulnerable. Whether an upload becomes remote code execution or just stored XSS depends almost entirely on your web server config, which makes this as much an ops problem as an application one.
What happened
E-commerce security firm Sansec published its PolyShell research on 17 March 2026. The bug sits in Magento's REST API, which accepts file uploads as part of a cart item's custom options. Mass exploitation began on 19 March, about two days after disclosure. Sansec's reporting cited by The Hacker News puts the first active exploitation on 16 March. By 25 March, BleepingComputer reported, Sansec had seen PolyShell attacks on 56.7% of all vulnerable stores. The Sansec research page has since been updated with higher figures.
Adobe had already changed the upload handling in the 2.4.9 pre-release branch, referenced in bulletin APSB25-94, and shipped it in 2.4.9-beta1 on 10 March 2026. At the time of the attacks no isolated patch existed for production 2.4.x releases, and Adobe did not give BleepingComputer a timeline. Sansec also reported a new skimmer in some suspected PolyShell intrusions. It loads its second stage over WebRTC, which uses DTLS-encrypted UDP, so it can slip past CSP connect-src rules and HTTP monitoring.
Who is affected
- Magento Open Source and Adobe Commerce 2.x stable releases without the 2.4.9 change or an equivalent mitigation.
- Stores whose web server serves or executes files under
pub/media/custom_options/. Adobe's sample nginx and Apache configs block this, but many stores run host-supplied configs that do not. - Agencies and hosts that maintain many Magento installs from a shared config template, because one weak template exposes every store built on it.
What it means for developers and engineering teams
The attack path is simple. An unauthenticated POST to /rest/default/V1/guest-carts/:cartId/items can include a file_info object (base64 data, MIME type, filename) inside custom_options. Assetnote's analysis says the product doesn't even need a file-type option configured. Magento writes the file to pub/media/custom_options/quote/<a>/<b>/<name>. A polyglot file passes image checks and still works as a script.
What happens next depends on the server:
- Apache: if
pub/media/custom_options/.htaccessis missing, the file can be served (stored XSS). Ifpub/media/.htaccesswithphp_flag engine 0is also missing, a.phpupload executes (RCE). RenamingAccessFileNamewithout renaming those files has the same effect. - nginx: removing Adobe's
deny allforcustom_optionsenables XSS. Removing the rule that stops PHP execution under/mediaenables RCE.
The general lesson applies far beyond Magento. Never let a user-upload directory be both web-reachable and executable, and don't rely on application-level MIME checks alone. Polyglots are built to pass them.
What to do now
- Upgrade to a release that contains the fix. Adobe moved it into the 2.4.9 line, so check Adobe's current security bulletins for your branch.
- Block the directory at the web server. Apache:
nginx (inside the Magento server block):<LocationMatch "^/media/custom_options/"> Require all denied </LocationMatch>location ^~ /media/custom_options/ { deny all; } location ~ ^/media/.*\.php$ { deny all; } - Consider an interim module. Mark Shust's community patch has been superseded by
aregowe/magento2-module-polyshell-protection. Review the code before you install it. - Hunt for uploads:
Anything that isn't an expected image is suspect. Reviewfind pub/media/custom_options/ -type f ! -name '.htaccess' -ls find . -name "accesson.php" -type f -ls.svgfiles carefully. - Check logs for
POSTrequests to/V1/guest-carts/*/itemscontainingfile_info, and compare source IPs with Sansec's published list. - Look for skimmers in CMS blocks, theme JS and checkout templates, and monitor for unexpected WebRTC/UDP egress. Sansec's eComscan is one free option.
- If you find a webshell, rebuild. Patching does not remove persistence. Rotate admin, database and payment-gateway credentials.
Related on TechLogHub
- Nginx vs Apache: how each one handles per-directory rules
- XSS: what stored cross-site scripting allows
- REST API: why unauthenticated endpoints need strict input rules
Sources
- Sansec: PolyShell, unrestricted file upload in Magento and Adobe Commerce
- Sansec: WebRTC skimmer research
- BleepingComputer: PolyShell attacks target 56% of all vulnerable Magento stores
- BleepingComputer: New PolyShell flaw allows unauthenticated RCE on Magento e-stores
- Assetnote / Searchlight Cyber: PolyShell technical analysis
- The Hacker News: Magento PolyShell flaw enables unauthenticated uploads
- Kudelski Security advisory

