Magento PolyShell (CVE-2026-48356) is now on CISA's exploited list, and its hidden script outlives patches. How to check your clients' stores.
One Magento shop had every core patch installed and had just passed a malware scan, and an hour later it was serving a stranger's script to its shoppers again. Sansec reported that case on October 24, 2026, and on October 27 the US cyber-defence agency CISA added PolyShell (CVE-2026-48356), the Adobe Commerce and Magento upload flaw this campaign used to break in, to its list of actively exploited bugs. The twist: the intruder was already inside, and the script lives in the store's database, which installing a patch doesn't clean.
Every Adobe Commerce and Magento Open Source release up to and including 2.4.9 is affected unless the July 14, 2026 isolated patch from Adobe's bulletin APSB26-73 is installed. Adobe tests that patch only on the latest security release of each line, so a store on 2.4.7-p1 must move to 2.4.7-p10 first. Adobe Commerce Cloud stores get the fix through the latest cloud-patches update instead.
| Product | Branch | Fixed in | Source |
|---|---|---|---|
| Adobe Commerce, Magento Open Source | 2.4.9 | 2.4.9-2026-jul | Adobe |
| Adobe Commerce, Magento Open Source | 2.4.8 (2.4.8-p5 and earlier) | 2.4.8-2026-jul | Adobe |
| Adobe Commerce, Magento Open Source | 2.4.7 (2.4.7-p10 and earlier) | 2.4.7-2026-jul | Adobe |
| Adobe Commerce, Magento Open Source | 2.4.6 (2.4.6-p15 and earlier) | 2.4.6-2026-jul | Adobe |
| Adobe Commerce | 2.4.5 (2.4.5-p17 and earlier) | 2.4.5-2026-jul | Adobe |
| Adobe Commerce | 2.4.4 (2.4.4-p18 and earlier) | 2.4.4-2026-jul | Adobe |
| Adobe Commerce B2B | 1.3.3 to 1.5.3 | matching 2026-jul patch | CVE record |
| Adobe Commerce Events | 1.20.0 and earlier | 1.21.0 | Adobe |
Magento PolyShell is the name Sansec, an e-commerce security firm, gave the bug when it first reported it on March 17, 2026: a hole in Magento's REST API, the interface apps use to talk to the store, that lets attackers with no login upload code disguised as an image. NVD, the US vulnerability database, rates it 9.3 out of 10; Adobe's bulletin scores it 9.6 and says no authentication is required. Both scores also list user interaction, but treat any unpatched store as reachable. CISA added it on October 27, 2026 and set a due date of November 10, 2026 for federal agencies. Sansec's October 24 report says one group used it, among other ways in, to plant a loader, a small script that fetches more code, on 953 stores since July 2025.
Check the database first: Sansec found the loader in the cms_block table on 148 server installs and never in the configuration table or theme files. Run these steps from a root shell on each client's web server; the searches cover every store under /var/www, /home and /srv, so add the hosting panel's web root if it differs. If sudo mysql asks for a password, add -u root -p. The campaign began in July 2025 and server logs rarely reach back that far, so search the client's SIEM (central log store) or log archive for older months; a clean on-server result does not rule out an earlier break-in.
Preserve evidence. This copies web logs, every database and the upload folders before anything changes, then records hashes.
D=/root/ir-polyshell-$(date +%F); sudo mkdir -p "$D"
sudo cp -a /var/log/apache2 /var/log/nginx /var/log/httpd "$D"/ 2>/dev/null
sudo mysqldump --all-databases --single-transaction | sudo tee "$D/all-databases.sql" >/dev/null
sudo find /var/www /home /srv -type d -path '*/pub/media/custom_options' -exec cp -a --parents {} "$D"/ \;
sudo find "$D" -type f -exec sha256sum {} + | sudo tee "$D.sha256"
Read each store's version. This reads the installed Magento release from Composer's lock file without running store code. Pass: the latest security release of its line, plus the Commerce Version Tool that ships with the July patch reporting CVE-2026-48356 as protected, per Adobe.
sudo find /var/www /home /srv -name composer.lock -not -path '*/vendor/*' -exec grep -H -A1 '"name": "magento/product-' {} \;
Search every store database for the loader. This uses Sansec's patterns plus the newest domain, deepveindrilling.com; update_time shows the attacker's latest write. Review each hit, since legitimate blocks can use localStorage too.
for t in $(sudo mysql -N -e "SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_name LIKE '%cms\_block' OR table_name LIKE '%cms\_page'"); do
echo "== $t"
sudo mysql -N -e "SELECT identifier, update_time FROM $t WHERE content LIKE '%fpCode%' OR content LIKE '%se_referrer%' OR content LIKE '%localStorage.getItem%' OR content LIKE '%deepveindrilling%'"
done
Find uploaded files and backdoors. Any file in these upload folders other than .htaccess is suspect, including fake PNG images, and accesson.php is a known backdoor name.
sudo find /var/www /home /srv -type f \( -path '*/pub/media/custom_options/*' -o -path '*/pub/media/customer_address/*' \) ! -name .htaccess
sudo find /var/www /home /srv -type f -name accesson.php
Search web logs for requests to scripts in the upload folder. A hit means someone ran code they uploaded.
sudo zgrep -hE 'media/custom_options/.*\.(php|phtml|phar)' /var/log/nginx/access.log* /var/log/apache2/access.log* /var/log/httpd/access_log* 2>/dev/null
List admin accounts in every store. Sansec found a rogue admin on the patched store; flag any name the client doesn't recognise.
for t in $(sudo mysql -N -e "SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_name LIKE '%admin\_user'"); do
echo "== $t"; sudo mysql -e "SELECT username, email, created, logdate, is_active FROM $t ORDER BY created DESC"
done
Check running processes and scheduled jobs. This shows children of the web and PHP workers (still-running processes only) and every user's cron jobs; anything besides Magento's own bin/magento cron:run needs an explanation.
ps -eo pid,ppid,user,comm,args --forest | grep -E -A3 'php-fpm|apache2|httpd|nginx'
sudo ls -la /etc/cron* /var/spool/cron/*
Indicators from Sansec's loader report and Sansec's PolyShell advisory.
Clean first, then patch, because the patch closes the upload hole but leaves the script and any backdoor in place.
Preserve evidence. Confirm step 1's hash file exists before changing anything: sudo ls -la /root/ir-polyshell-*.sha256.
Contain the upload folder. On nginx, add Sansec's rule before any \.php$ location block, then run sudo nginx -t && sudo systemctl reload nginx. Blocking web access does not stop uploads; only the patch or a web application firewall (WAF) that blocks the API call does, per Sansec.
location ~* ^/pub/media/custom_options/ {
deny all;
return 403;
}
On Apache, confirm each upload folder's .htaccess disables PHP and denies access; pass: every line ends in :2.
sudo find /var/www /home /srv -path '*/pub/media/custom_options/.htaccess' -exec grep -H -c -E 'php_flag engine 0|Deny from all' {} \;
Remove the foothold. Delete the injected script from each block or page step 3 listed, delete the files step 4 found, and disable admin accounts from step 6 that nobody recognises. Pass: rerun steps 3, 4 and 6 and get no unexplained results.
Change passwords. Change the database password (and update it in the store's app/etc/env.php), every admin password and every API integration key. Pass: logging in with the old database password fails.
Patch. Move to the latest security release of the store's line, apply APSB26-73, and install APSB25-88 for SessionReaper (CVE-2025-54236), per Sansec. Pass: step 2 shows CVE-2026-48356 as protected.
Adobe's patch changes Magento's code, while the loader is stored as content in the Magento cms_block table, and any access the attacker already holds, such as a rogue admin account, outlives the patch. That is how the 2.4.7-p10 store got deepveindrilling.com at 16:46 UTC on October 23, an hour after a clean scan, per Sansec: a rogue admin account had been sitting there since September 16, and a GSocket backdoor, a remote-access tool, since September 24.
Three more findings from the same report:
deepveindrilling.com, 60 already ran an earlier loader from the same operator; the report doesn't say how the other 23 were breached.The same operator put its loader on 471 stores in one hour on March 30, 2026, per Sansec.
KinoSec doesn't read store databases, so it won't find a script sitting in cms_block; steps 3 and 6 above do that. What it tests is the way in. PolyShell needed no login on stores open to the internet, and a missed patch left that door open for months. KinoSec runs autonomous web app pentests against your clients' stores: reconnaissance, finding vulnerabilities, chaining exploits and writing up findings with remediation, continuously and on demand. It tests what an attacker could reach from the outside, so a store that slips behind on patches shows up in the report you hand your client, not in Sansec's next count.
Nobody knows yet. Sansec has not recovered the final payload, so the campaign's goal is unknown. In December 2025, Sansec saw an earlier stage send a logged-in customer a script from leqdger.click, a domain imitating the crypto wallet brand Ledger.
sudo find /var/www /home /srv -type f -name accesson.php.No. Sansec says blocking web access to the upload folder does not stop the uploads themselves; only Adobe's APSB26-73 patch or a WAF that blocks the API call does.
It can be. Since October 23, the loader checks whether the visitor is an automated browser, and urlscan.io found no added content on an infected store. Search the cms_block table directly.