The Magento vulnerability known as PolyShell, CVE-2026-48356, lets anyone upload an executable file to a Magento Open Source or Adobe Commerce store through the guest cart API, with no login. CISA added it to the KEV catalog on October 27, 2026, with a federal due date of November 10. If your store ran an unpatched build at any point since March 2026, installing the patch is only half the job, because the attackers’ code may already sit in your database.
That is the part most coverage of PolyShell skips. On October 23, Sansec watched a store on 2.4.7-p10 with no missing core patches receive a fresh skimmer loader one hour after a clean scan. A rogue admin account had been sitting on it since September 16, so the patch closed a door the intruder no longer needed.
What happened, from March to KEV
The flaw spent almost four months in the wild before the fix reached the release lines most stores actually run. Sansec named and disclosed PolyShell on March 17, 2026, saw the first attacks on March 19 and mass scanning from March 23. On March 30 a single wave compromised 471 stores in one hour. Adobe shipped the fix in Magento 2.4.9 on May 12, but only backported it to the supported 2.4.8, 2.4.7 and 2.4.6 lines on July 14 with security bulletin APSB26-73, and NVD published the CVE record the same day with a link to it.
Read the bulletin today and it still says Adobe “is not aware of any exploits in the wild.” CISA’s listing settles that question, and so does Sansec’s count of exploitation attempts against 79.5% of the Magento stores its firewall protects. We would not wait for the bulletin to catch up before treating this as an incident.
Which Magento and Adobe Commerce versions are affected
APSB26-73 lists these builds as affected, with a July 2026 build as the fix for each release line.
| Product | Affected | Fixed |
|---|---|---|
| Adobe Commerce | 2.4.9, 2.4.8-p5, 2.4.7-p10, 2.4.6-p15, 2.4.5-p17, 2.4.4-p18 and earlier | 2.4.9-2026-jul, 2.4.8-2026-jul, 2.4.7-2026-jul, 2.4.6-2026-jul, 2.4.5-2026-jul, 2.4.4-2026-jul |
| Magento Open Source | 2.4.9, 2.4.8-p5, 2.4.7-p10, 2.4.6-p15 and earlier | 2.4.9-2026-jul, 2.4.8-2026-jul, 2.4.7-2026-jul, 2.4.6-2026-jul |
| Adobe Commerce B2B | 1.5.3, 1.5.2-p5, 1.4.2-p10, 1.3.4-p17, 1.3.3-p18 and earlier | 1.5.3-2026-jul, 1.5.2-2026-jul, 1.4.2-2026-jul, 1.3.4-2026-jul, 1.3.3-2026-jul |
The scores disagree slightly. Adobe rates it 9.6 with a small availability impact, while NVD records 9.3. Both vectors mark user interaction as required, and NVD’s description says a victim must visit a crafted URL. Sansec’s research shows the file upload itself needs no victim at all.
How the PolyShell attack works
Magento’s REST API lets a shopper attach a file to a cart item when a product has a file-type custom option. Sansec’s analysis shows that the code accepts a file_info object with base64 data, a MIME type and a filename, then writes it to pub/media/custom_options/quote/ without checking that the option exists, that it is a file option, or that the extension is safe. The only check is an image header test, so a GIF or PNG with PHP appended passes, which is where the polyglot name comes from. The anonymous routes POST /V1/guest-carts/:cartId/items and PUT /V1/guest-carts/:cartId/items/:itemId make it reachable without credentials. GraphQL takes a different path and is not affected.
Whether the upload becomes code execution depends on your web server. Stock nginx configurations on 2.0.0 to 2.2.x, custom nginx setups that pass every .php file to FastCGI, and Apache before 2.3.5 without php_flag engine 0 will all run the shell. Everyone else still has the file on disk, which turns dangerous the day someone migrates the server.
From there the chain is automated. The webshell drops a backdoor called accesson.php into an assets/images/ folder under every top-level directory it can write to, and that backdoor answers every request with the beacon string 8194460 so the operator can find live shells at scale. Then a JavaScript loader goes into the cms_block table, the static blocks Magento renders on storefront pages.
Why patched is not clean
The patch closes the upload path, and it does nothing about what already came through it. The current loader stores its payload in the shopper’s browser under the localStorage key fpCode and replays it on every page view, even when the loader domain is blocked. It also fingerprints visitors and serves nothing to automated browsers, so a quick scan of your own storefront can come back clean while real visitors are treated differently.
The operator behind it has been at this since July 2025 and has reached 953 stores, rotating through five loader domains. Of the 83 stores on the newest one, 60 were already infected by an earlier domain. The domain changed and the access did not.
The link to unpatched stores is plain in Sansec’s data. Of 169 Magento 2 installs carrying the loader and missing at least one core patch, 102 also held files uploaded through PolyShell or through SessionReaper, an older Magento flaw. Magento is a PHP application, so the runtime layer matters here too, which we covered in our PHP vulnerability post on October 22.
How to detect PolyShell exploitation
Access logs rarely record request bodies, so you will not see the file_info payload itself. What you can see is the attacker coming back to use what they planted, because a webshell is only useful once someone requests it. The Sigma rule below maps to T1190 and T1505.003.
Data source: web server or reverse proxy access logs in front of Magento (nginx, Apache, a CDN or WAF log export), Sigma webserver category
title: Magento PolyShell Webshell Access
id: 4f8a2c61-9d3e-4b7a-a1c5-6e0b9d2f7a13
status: experimental
description: Detects requests for executable files in the Magento custom options upload folder and for the accesson.php backdoor, both seen after PolyShell (CVE-2026-48356) uploads.
references:
- https://sansec.io/research/magento-polyshell
- https://sansec.io/research/polyshell-mass-attack-wave
author: MarkCyber Research
date: 2026-10-28
tags:
- attack.initial-access
- attack.persistence
- attack.t1190
- attack.t1505.003
- cve.2026-48356
logsource:
category: webserver
detection:
selection_upload_dir:
cs-uri-stem|contains: '/media/custom_options/'
cs-uri-stem|endswith:
- '.php'
- '.phtml'
- '.phar'
selection_backdoor:
cs-uri-stem|endswith: '/accesson.php'
condition: 1 of selection_*
falsepositives:
- Vulnerability scanners and penetration tests probing the same paths
- Storefront traffic never requests PHP under custom_options, so treat other hits as an incident
level: high
It fires on probes even when your server answers 403, which is useful because a probe tells you someone tried. It cannot see an attacker who renamed the backdoor or who only used the stored XSS path, and it says nothing about the loader once it sits in the database. So pair it with on-box checks. List every file in pub/media/custom_options/ and pub/media/customer_address/ other than .htaccess, search the whole document root for accesson.php, search the content column of cms_block and cms_page for fpCode, se_referrer and localStorage.getItem, and review admin_user for accounts you did not create. Search back to March 16, 2026, when Sansec saw the first probes.
Mitigation
- Install APSB26-73, or upgrade to the July 2026 build of your release line. Add APSB25-88 for SessionReaper if it is missing too.
- Block web access to
pub/media/custom_options/with the nginxdenyor Apache.htaccessrules in Sansec’s advisory. That stops execution but not uploads, so it backs up the patch rather than replacing it. - Run the on-box checks above. If anything turns up, remove the loader, the shells and any rogue admins, then change the database, admin and API integration passwords, as Sansec advises, because the attacker could write to your database.
A store that takes card payments is exposed in a way no patch window fixes on its own, which is why our security engineering work starts with what is already on the box.
Bottom line
Patch to the July 2026 build before November 10, then prove the store is clean by checking the upload folder, accesson.php, the CMS tables and the admin list. Put the Sigma rule on your access logs and hunt back to March 16.
