PolyShell: what is established, where sources differ
CVE-2026-48356, nicknamed PolyShell, affects Adobe Commerce and Magento Open Source. The NVD entry, published on July 14, 2026 from Adobe's submission, classifies it as CWE-434 (unrestricted upload of a file with a dangerous type), with a CVSS 3.1 score of 9.3 and the vector AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N. The fix is Adobe bulletin APSB26-73. On October 27, 2026, CISA added it to its Known Exploited Vulnerabilities (KEV) catalog, with a November 10, 2026 deadline for US federal agencies: exploitation is no longer a hypothesis.
The sources do not describe the flaw the same way. NVD describes arbitrary code execution "in the context of the current user" that requires interaction: a victim has to visit a crafted URL or a compromised page, and the impact reaches beyond the vulnerable component. Sansec and the specialist press describe file uploads that end in webshells on the server. We do not decide between these two readings. The prudent course for an agency is to treat every store still missing the fix as a store that may already carry a webshell.
What the sources say, and what you take from them
Scroll the table
| Source | What it states | What you take from it |
|---|---|---|
| NVD | CWE-434, CVSS 3.1 score of 9.3, interaction required, execution in the context of the current user | The identifiers to record in the client file |
| CISA, KEV catalog | Exploitation observed, added on October 27, 2026, federal deadline of November 10, 2026 | A working horizon, not a comfortable date |
| Adobe, bulletin APSB26-73 | Versions with the 2026-jul suffix are not affected | The target version for each branch |
| Sansec, March 30, 2026 | Mass attack wave: 471 stores compromised in one hour, a PHP webshell followed by `accesson.php` backdoors | The files to look for on disk |
| Sansec, October 24, 2026 | JavaScript loader in `cms_block`, a campaign tracked since July 2025 across 953 stores; 102 of 169 unpatched installations carried uploaded files | The queries to run on the database |
| Specialist press | File uploads leading to webshells | A reading to cross-check, not a primary source |
Why the patch does not close the case
Applying APSB26-73 removes the flaw. It removes nothing that has already come in. A webshell dropped before the update stays on disk, an accesson.php backdoor keeps answering, a script injected into cms_block keeps being served to every visitor, and an admin account created by the attacker stays valid. Sansec puts it this way: removing the scripts does not remove the attacker's access.
Sansec's second study shows why the question applies to a whole portfolio. Of 169 unpatched Magento 2 installations examined, 102 carried files uploaded through PolyShell or SessionReaper (CVE-2025-54236, fixed by bulletin APSB25-88), which is 60%. The order of work is therefore fixed: inventory, frozen state, update, search for traces, credential rotation, then a dated status report for the client. Skipping the rotation to save an hour leaves the attacker the keys they may already have copied.
What this procedure leaves in your hands
- An inventory per store — edition (Commerce or Open Source), exact version, whether the 2026-jul fix is present.
- A target version per branch — read from bulletin APSB26-73, with no guessing at the numbering.
- A frozen state before any work — snapshot and database export kept as evidence, before any cleanup.
- Four repeatable checks — files under
pub/media,accesson.phpbackdoors, JavaScript incms_blockand incms_page. - A complete credential rotation — admin accounts, API and integration keys, database, encryption key, SSH and SFTP.
- A dated status report for each client — what was checked, found and fixed, and what was not.
Affected and fixed versions according to APSB26-73
Scroll the table
| Product and branch | Affected up to | Fixed version |
|---|---|---|
| Adobe Commerce 2.4.9 | 2.4.9 | 2.4.9-2026-jul |
| Adobe Commerce 2.4.8 | 2.4.8-p5 | 2.4.8-2026-jul |
| Adobe Commerce 2.4.7 | 2.4.7-p10 | 2.4.7-2026-jul |
| Adobe Commerce 2.4.6 | 2.4.6-p15 | 2.4.6-2026-jul |
| Adobe Commerce 2.4.5 | 2.4.5-p17 | 2.4.5-2026-jul |
| Adobe Commerce 2.4.4 | 2.4.4-p18 | 2.4.4-2026-jul |
| Magento Open Source 2.4.9 | 2.4.9 | 2.4.9-2026-jul |
| Magento Open Source 2.4.8 | 2.4.8-p5 | 2.4.8-2026-jul |
| Magento Open Source 2.4.7 | 2.4.7-p10 | 2.4.7-2026-jul |
| Magento Open Source 2.4.6 | 2.4.6-p15 | 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 | 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 |
| Adobe Commerce Events | 1.20.0 and earlier | 1.21.0 |
| Magento Open Source 2.4.5 and 2.4.4 | Not in the NVD list | No conclusion: read the Adobe advisory |
Inventory the version of every store
Read the declared version
cd /var/www/client-storebin/magento --version
The command prints the edition and the number. The path is an example: adapt it to each hosting setup. Run it as the system user that owns the files, not as root, so you do not change the cache permissions.Cross-check with Composer
composer show magento/product-community-edition
for Magento Open Source, orcomposer show magento/product-enterprise-edition
for Adobe Commerce. Composer reads what is actually installed. If the two readings differ, Composer is authoritative, and the gap gets recorded.Sweep an entire server
find /var/www /home -name composer.lock -not -path '*/vendor/*' -exec grep -H -A1 '"name": "magento/product-' {} +
Each file listed belongs to a Magento installation, and theversionline follows the package name. A public staging site or an old unpacked copy counts as a store: it is exposed in the same way if it is served.Classify with the version table
Compare the number you found with the table above. Reading rule: any version without the 2026-jul suffix for its branch needs action. For Magento Open Source 2.4.5 and 2.4.4, which are not in the NVD list, do not write "not affected": refer to the Adobe bulletin and treat the store as exposed until you have read otherwise.
Record one row per store
Client, server, path, edition, version found, date and time of the check. Add right away the columns you will need later: fix applied, result of the four checks, credentials rotated. This table becomes the central document of the file handed to the client.
Freeze the state before touching anything: it is also evidence
Before any change, freeze the store as you found it. On a VPS, a VPS snapshot, if your host offers one, captures the whole disk; add a database export and a code archive on storage the update does not touch. The difference between the two tools is covered in our snapshot versus backup comparison.
This state serves twice. It lets you roll back if the update breaks checkout. Above all, it preserves evidence: if the attacker got in, the dropped files, their dates and the modified CMS blocks are in this copy, and nowhere else once the cleanup is done. CISA also points to its forensic triage requirements for affected systems. Do not delete or overwrite this state until the case is closed.
A branch upgrade, from 2.4.6 to 2.4.9 for example, is a separate project: its Composer procedure and support calendar are in our upgrade guide. Here, each store stays on its branch and only receives the fix.
Apply the fix without a long outage
Rehearse on a staging copy
Restore the frozen state to a staging environment, or clone the store, and run the update there first. Time each command: that duration sets the maintenance window you announce to the client.
Pin the fixed version
composer require magento/product-community-edition=<fixed-version> --no-update
Replace the package withmagento/product-enterprise-editionfor Adobe Commerce, and<fixed-version>with the 2026-jul version of your branch, exactly as the bulletin writes it.Resolve and validate the lock file
composer update magento/product-community-edition --with-all-dependencies
Review the list of changed packages. Thecomposer.lockyou obtain and test is the one you will deploy: production no longer resolves anything, it installs.Open the maintenance window in production
bin/magento maintenance:enablebin/magento maintenance:allow-ips <your-ip>
Everything before this point happened without stopping sales. The second command lets you test the store before it reopens.Install and apply
composer install --no-devbin/magento setup:upgradebin/magento setup:di:compilebin/magento setup:static-content:deploy
With a lock file already validated, the outage is limited to these four commands.Reopen and verify
bin/magento maintenance:disablecomposer show magento/product-community-edition
The installed version must be the fixed version of your branch. Place an order with the payment gateway in test mode, then record the version and time in the table.
Look for traces of compromise
List files dropped under pub/media
find pub/media/custom_options/ pub/media/customer_address/ -type f ! -name '.htaccess'
A command published by Sansec, to run from the store root. Every file listed needs review, especially a PHP script. Copy it outside the public tree with its modification date before deleting it.Search for accesson.php backdoors
find . -name 'accesson.php' -type f
Sansec reports this file "in multiple directories": run the search from the root, not only underpub/. An empty result proves that this particular file is absent, not that no backdoor exists.Query the cms_block table
SELECT block_id, identifier, update_time FROM cms_block WHERE content LIKE '%fpCode%' OR content LIKE '%se_referrer%' OR content LIKE '%localStorage.getItem%';
A query published by Sansec. Add the installation's table prefix if there is one. Theupdate_timecolumn helps date the injection.Query the cms_page table
SELECT page_id, identifier, update_time FROM cms_page WHERE content LIKE '%fpCode%' OR content LIKE '%se_referrer%' OR content LIKE '%localStorage.getItem%';
The same check on CMS pages. A result is not necessarily malicious:localStorage.getItemcan appear in a legitimate script. Read the content before concluding.Match against published indicators
For the March 2026 wave, Sansec published a loader domain,
lanhd6549tdhse.top, a localStorage key,136c1e07507f4a97, and a backdoor marker,8194460. Look for them in the previous results and in the files you found, for example withgrep -rl 'lanhd6549tdhse' pub/ app/. This list is not exhaustive: their absence does not clear a store.Check administrator accounts
SELECT user_id, username, email, created, logdate, is_active FROM admin_user ORDER BY created DESC;
An account nobody recognizes, or one created close to the date of a suspicious file, gets disabled and then documented. The monthly check of these points on each client VPS is described in our audit checklist.
Hardening: PHP has no business under pub/media
Independently of PolyShell, a directory that receives files sent by visitors should never execute PHP. Check that your nginx or Apache configuration refuses to execute scripts under pub/media, and test it on staging with a harmless file. This is not a mitigation published by Adobe for this CVE, and it does not replace the fix: it is general hardening that reduces the effect of a future successful upload.
Troubleshooting: common blockers during the procedure
"Your requirements could not be resolved to an installable set of packages." Composer refuses the requested version: a third-party module pins a dependency, or the stability constraint in composer.json excludes the target version. The command composer why-not magento/product-community-edition <fixed-version> names the package that blocks. Sort it out on staging, never in production.
"Please upgrade your database: Run "bin/magento setup:upgrade" from the Magento root directory." The store shows this message after the code update: the setup:upgrade step was not run, or it failed. Run it again, then the compilation.
"Table '…cms_block' doesn't exist" when running the Sansec query: the installation uses a table prefix. Read the prefix in the store configuration and add it to the table name.
"No such file or directory" on the pub/media find command: the custom_options or customer_address directory does not exist on this store. Record it in the table; it is neither a failure nor proof that the store is clean.
A store that stays in maintenance: check that no maintenance flag remains and run bin/magento maintenance:disable again as the user that owns the files.
After the cleanup: what must be rotated
- Administrator passwords — every account in
admin_user, including the ones you consider sound. - API keys and integrations — tokens of the integrations declared in the admin, keys for third-party services (payment, shipping, ERP) stored in the configuration.
- Database credentials — a new password, updated in the store configuration.
- Encryption key — to be changed following the Adobe documentation, after assessing the effect on data that is already encrypted.
- SSH and SFTP access — passwords, authorized SSH keys, unknown system accounts.
- Hosting access — control panel and backups, which also give access to the files.
The dated status report to hand to each client
Scroll the table
| Column | What you write | Why |
|---|---|---|
| Version before and after | Numbers read by Composer, with date and time | Shows that the APSB26-73 fix is in place |
| Frozen state | Reference of the snapshot and of the database export | Allows rollback and forensic review |
| Files under pub/media | Paths and dates of the files found, or "none" | Check published by Sansec |
| accesson.php | Paths found, or "none" | Backdoor reported by Sansec |
| cms_block and cms_page | Identifiers listed and verdict after reading | Injected JavaScript served to visitors |
| Admin accounts | Unknown accounts disabled, or "none" | Access left by the attacker |
| Credentials rotated | Secrets changed and date of the change | Closes what the attacker may have copied |
| Not checked | What you could not look at, and why | An honest status beats an "all is well" |
What you keep, and the sources to cite
When a store is found compromised, the agency is the one the client calls. Keep that role: you hold the relationship, the diagnosis and the dated report; the platform holds the infrastructure, the root access to the VPS that lets you run these checks, and the snapshot before any work. We do not change a store's code on your behalf: updating Magento remains the agency's task. Keep the table template as well: the next flaw affecting a store will follow the same sequence, with one more row in the inventory.
Primary sources:
NVD entry for CVE-2026-48356
Adobe bulletin APSB26-73
CISA alert of October 27, 2026
Sansec, PolyShell mass attack wave
Sansec, JavaScript loader in cms_block