# aregowe/magento2-module-polyshell-protection

> Comprehensive defense-in-depth module that closes the PolyShell unrestricted file upload vulnerability (APSB25-94) in Adobe Commerce and Magento Open Source.

`composer require aregowe/magento2-module-polyshell-protection`

Canonical URL: https://packagento.com/aregowe/magento2-module-polyshell-protection

## At a glance

- **Vendor**: aregowe (https://packagento.com/aregowe.md)
- **Latest version**: 1.3.4 — released 2026-04-23
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/aregowe/magento2-module-polyshell-protection and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require aregowe/magento2-module-polyshell-protection:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Comprehensive defense-in-depth module that closes the PolyShell unrestricted file upload vulnerability (APSB25-94) in Adobe Commerce and Magento Open Source.

## README

### Purpose

Comprehensive defense-in-depth module that closes the **PolyShell** unrestricted file upload vulnerability (APSB25-94) in Adobe Commerce. PolyShell affects all Magento Open Source and Adobe Commerce versions up to 2.4.9-alpha2. No official isolated patch exists for production versions.

This module was originally forked from [markshust/magento2-module-polyshell-patch](https://github.com/markshust/magento-polyshell-patch) by [Mark Shust](https://github.com/markshust). With Mark's permission, his module's logic has been fully integrated into this one, and he has deprecated his package in favor of this module.

**Reference:** [Sansec — PolyShell: unrestricted file upload in Magento and Adobe Commerce](https://sansec.io/research/magento-polyshell)

If this module helped protect your store, consider [buying me a coffee ☕](https://ko-fi.com/aregowe) — it helps me keep maintaining and improving it.

### Installation

#### Via Composer (recommended)

```bash
composer require aregowe/magento2-module-polyshell-protection
bin/magento module:enable Aregowe_PolyShellProtection
bin/magento setup:upgrade
bin/magento cache:flush
```

#### Manually

Copy the module into your project:

```bash
mkdir -p app/code/Aregowe/PolyShellProtection
cp -r * app/code/Aregowe/PolyShellProtection/
bin/magento module:enable Aregowe_PolyShellProtection
bin/magento setup:upgrade
bin/magento cache:flush
```

#### Uninstallation

```bash
bin/magento module:disable Aregowe_PolyShellProtection
bin/magento setup:upgrade
composer remove aregowe/magento2-module-polyshell-protection
bin/magento cache:flush
```

### Migrating from MarkShust_PolyshellPatch

This module **integrates and supersedes** [markshust/magento2-module-polyshell-patch](https://github.com/markshust/magento-polyshell-patch). You do **not** need both modules — this one includes all of Mark Shust's original protection and extends it significantly.

Mark Shust's module provided a focused two-plugin fix that enforced a 4-extension image allowlist (`jpg`, `jpeg`, `gif`, `png`) on `ImageContentValidator` and `ImageProcessor`. That logic is now fully integrated into this module's `HardenImageContentValidatorPlugin` and `HardenImageProcessorPlugin`, which add:
- Polyglot file scanning (detects valid images with embedded PHP)
- No-extension and double-extension attack detection
- Multi-pass URL decoding and obfuscation normalization
- Known attack filename/pattern matching
- Request path blocking at the FrontController and `pub/get.php` level
- Controller-level upload blocking for customer attribute and file upload endpoints
- Configurable filename validation for custom option file uploads via the Webapi File Processor, with admin-configurable allowed and blocked extension lists

The `composer.json` includes a `"replace"` directive for `markshust/magento2-module-polyshell-patch`, so Composer will automatically handle the transition.

#### If you currently have MarkShust_PolyshellPatch installed

```bash
bin/magento module:disable MarkShust_PolyshellPatch
bin/magento setup:upgrade
composer require aregowe/magento2-module-polyshell-protection
bin/magento module:enable Aregowe_PolyShellProtection
bin/magento setup:upgrade
bin/magento cache:flush
```

Composer's `replace` directive will remove MarkShust's package automatically when this module is installed.

#### Credits

This module was forked from [markshust/magento2-module-polyshell-patch](https://github.com/markshust/magento-polyshell-patch), created by [Mark Shust](https://github.com/markshust) and sponsored by [M.academy](https://m.academy/). Mark gave his permission to integrate his module's logic into this one and has deprecated his package in favor of this project. Thank you, Mark!

### Vulnerability Summary

Magento's REST API accepts file uploads as part of 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 from core Magento:

1. **No option ID validation** — the submitted option ID is never verified against the product's actual options.
2. **No option type gating** — file upload logic triggers regardless of whether the product has a file-type option.
3. **No file extension restriction** — extensions like `.php`, `.phtml`, and `.phar` are not blocked. The only validation is `getimagesizefromstring`, which is trivially bypassed using polyglot files (valid image headers containing embedded PHP).

The most dangerous endpoints are the anonymous guest cart routes:

| Method | Endpoint | Auth Required |
|--------|----------|---------------|
| POST | `/V1/guest-carts/:cartId/items` | None |
| PUT | `/V1/guest-carts/:cartId/items/:itemId` | None |

#### Live Attack Patterns

Attackers upload **polyglot files** — valid GIF or PNG images containing executable PHP. Two payload types are in active use:

- **Cookie-authenticated webshell** — GIF89a polyglot dropped as `index.php`, verifies cookie against hardcoded MD5 hash, executes arbitrary code via `eval(base64_decode())`.
- **Password-protected RCE shell** — uses `hash_equals()` with double-MD5 hash, passes commands to `system()`.

Common attack filenames: `index.php`, `780index.php` (option_id prefix), `json-shell.php`, `bypass.phtml`, `rce.php`, `shell.php`, `accesson.php`, `test.php`, `ato_poc.html`.

Post-exploitation deploys `accesson.php` backdoors across writable directories (`app/assets/images/`, `var/assets/images/`, `vendor/assets/images/`, etc.) and injects JavaScript malware loaders into CMS content.

### How This Module Protects

This module implements **eight layered Magento plugins** and **three security models** that block the attack at every interception point. If one layer is bypassed, subsequent layers catch it.

#### Defense Layers (in execution order)

_(README truncated for .md surface. Full README on https://packagento.com/aregowe/magento2-module-polyshell-protection.)_

## Recent Versions

| Version | Released |
|---|---|
| 1.3.4 | 2026-04-23 |
| 1.3.3 | 2026-04-22 |
| 1.3.2 | 2026-04-21 |
| 1.3.1 | 2026-04-20 |
| 1.3.0 | 2026-04-20 |
| 1.2.1 | 2026-04-20 |
| 1.2.0 | 2026-04-18 |
| 1.1.0 | 2026-04-14 |
| 1.0.2 | 2026-04-14 |
| 1.0.1 | 2026-04-14 |

Showing 10 of 11 versions. Full release history on https://packagento.com/aregowe/magento2-module-polyshell-protection.

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | ^103 |
| php | ^8.1 |

### Require (dev)

| Package | Constraint |
|---|---|
| phpunit/phpunit | ^10.5 |
| roave/security-advisories | dev-latest |

### Replace

| Package | Constraint |
|---|---|
| markshust/magento2-module-polyshell-patch | * |

## Quality

Latest release (1.3.4) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | Pass |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Warning | 91 | 91 warnings (ruleset: Magento2) — 3 auto-fixable with phpcbf |
| PHPMD | Warning | 28 | 28 rule violations (UnusedFormalParameter:9, MissingImport:6, NPathComplexity:4, TooManyPublicMethods:4, UnusedLocalVariable:2) |
| Cpd | Warning | 2 | 2 duplicated chunks spanning 54 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Info | 1 | valid; 1 advisory note (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 7 | 7 | – | – |
| 2.4.8 | – | 8 | 8 | – |
| 2.4.9 | – | – | 8 | 8 |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Fail | 3 | malware detected — 3 signature matches (WEBSHELL_PHP_Gzinflated:1, WEBSHELL_PHP_Dynamic_Big:1, EXT_WEBSHELL_PHP_Generic:1) |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["aregowe/magento2-module-polyshell-protection"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

aregowe is a Magento 2 vendor on Packagento. See https://packagento.com/aregowe.md for their full catalogue.

