← Back to Feed CACHED · 2026-10-26 20:26:31 · CACHE_KEY CVE-2026-48356
CVE-2026-48356 · CWE-434 · Disclosed 2026-07-14

Adobe Commerce guest-cart REST API unrestricted polyglot file upload (PolyShell)

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Someone left the warehouse loading dock wide open and attackers are already driving trucks through it

CVE-2026-48356, dubbed PolyShell by Sansec, is an unrestricted file upload vulnerability in Magento's guest-cart REST API (POST /V1/guest-carts/{cartId}/items). The flaw exists because the ImageContentValidator only checks image headers via getimagesizefromstring() — never the file extension — and ImageProcessor::getFileName preserves the caller-supplied extension. An attacker sends a single unauthenticated POST containing a polyglot file (GIF89a magic bytes prepended to PHP code, saved as .php), which lands in the web-accessible pub/media/custom_options/quote/ directory and executes as the Magento web user. Every version of Adobe Commerce from 2.4.4 through 2.4.9 (all patch levels), Magento Open Source 2.4.6–2.4.9, and Commerce B2B 1.3.3–1.5.3 are affected. Sansec reports the underlying flaw has existed since the first Magento 2 release.

Adobe rates this CRITICAL at 9.3 (CVSS:3.1 with UI:R), but the vendor vector understates reality. The actual REST API attack path documented by Sansec and reproduced by Abraxas Labs requires zero user interaction — the attacker sends a POST and directly accesses the uploaded shell. With UI:N, the recalculated CVSS exceeds 9.8. More importantly, this is not theoretical: as of March 2026, Sansec Shield recorded exploitation attempts against 79.5% of monitored Magento stores, and a campaign tied to deepveindrilling[.]com has compromised 953+ online stores with JavaScript skimmers and accesson.php backdoors. Active exploitation evidence and a public weaponized PoC mean the noisgate mitigation SLA is overridden: patch or mitigate immediately, within hours. The noisgate remediation SLA for CRITICAL is ≤90 days, but given active exploitation, you should treat the vendor patch as an emergency deployment — not a quarterly cycle item.

"PolyShell is as bad as it sounds: unauthenticated RCE on every Magento store, actively exploited at scale"
02 · The Attack Path

5 steps from start to impact.

STEP 01

Enumerate target Magento instance

The attacker identifies an internet-facing Magento or Adobe Commerce store. Magento's default responses, HTTP headers (X-Magento-*), and characteristic URL patterns (/rest/V1/, /pub/static/) make fingerprinting trivial. Shodan and FOFA index approximately 50,000 exposed Magento instances.
Conditions required:
  • Internet-facing Magento/Adobe Commerce instance running any version ≤2.4.9 (unpatched)
Where this breaks in practice:
  • None — Magento stores are internet-facing by design and easily fingerprinted
Detection/coverage: Shodan dork http.component:Magento; Nuclei template magento-detect
STEP 02

Create a guest cart via REST API

The attacker issues POST /rest/default/V1/guest-carts which returns a cartId string. This is a legitimate, unauthenticated, public API endpoint designed for guest checkout. No credentials, tokens, or session cookies are required.
Conditions required:
  • Guest checkout REST API is enabled (default in all Magento installations)
Where this breaks in practice:
  • Virtually none — disabling the guest-cart API breaks guest checkout, a core business function
Detection/coverage: Anomalous cart creation volume may trigger rate-limit alerts, but a single request suffices
STEP 03

Upload polyglot PHP shell via cart item

The attacker sends POST /rest/default/V1/guest-carts/{cartId}/items with a JSON body containing a custom_options[].file_info object. The base64-encoded payload starts with GIF89a magic bytes (passing getimagesizefromstring()), followed by PHP code (<?php system($_GET['cmd']); ?>). The filename ends in .php. Three missing validation checks — no option ID validation, no option type gating, no extension restriction — allow the file to be written verbatim to pub/media/custom_options/quote/. The API response JSON includes the exact filename. Weaponized tool: abraxas/CVE-2026-48356 (Python).
Conditions required:
  • Target has not applied APSB26-73 patch
  • pub/media/ directory is web-accessible (default Magento layout)
Where this breaks in practice:
  • A WAF inspecting REST API bodies for polyglot signatures could block this, but most WAF rulesets do not inspect base64-decoded content inside JSON payloads by default
Detection/coverage: WAF rules matching GIF89a followed by <?php in base64-decoded POST bodies; file integrity monitoring on pub/media/custom_options/
STEP 04

Execute uploaded webshell

The attacker issues GET /media/custom_options/quote/{filename}.php?cmd=id and receives command output as the web server user (typically www-data or apache). The Magento web user typically has read access to app/etc/env.php, which contains database credentials, encryption keys, and Redis/RabbitMQ secrets.
Conditions required:
  • PHP execution is enabled in the pub/media/ directory (default Apache/Nginx Magento configs)
Where this breaks in practice:
  • Disabling PHP execution in pub/media/ via .htaccess or Nginx location blocks would break this step
Detection/coverage: Web server access logs showing .php requests under /media/custom_options/; EDR/HIDS detecting new PHP files in media directories
STEP 05

Establish persistence and exfiltrate data

In observed campaigns, attackers deploy persistent backdoors (accesson.php) across multiple directories and inject JavaScript skimmers into CMS blocks to exfiltrate payment card data from checkout pages. Database credentials from env.php provide direct access to customer PII, order history, and stored payment tokens. The deepveindrilling[.]com campaign demonstrates the full chain: polyglot upload → backdoor → JavaScript loader → card skimmer across 953+ stores.
Conditions required:
  • Initial webshell execution (Step 4)
Where this breaks in practice:
  • Content Security Policy headers may block inline script injection on some stores, but CSP adoption in Magento stores is low
Detection/coverage: Sansec eComscan, Magento Security Scan Tool, or custom YARA rules for accesson.php and known skimmer patterns; CSP violation reports
03 · Compensating Control

1
CRITICAL 9.8→HIGH 7.5
SEVERITY REDUCED
Disable PHP execution in pub/media/ immediately — Add php_flag engine off in .htaccess or location ~ \.php$ { deny all; } in the Nginx config for the pub/media/ directory tree. This breaks the execution step of the chain — uploaded shells become inert text files. This is a zero-downtime change that does not affect Magento functionality since pub/media/ should only serve static assets. Given active exploitation, deploy within hours, not days.
2
CRITICAL 9.8→MEDIUM 5.5
SEVERITY REDUCED
Block polyglot uploads via WAF rule on guest-cart API — Deploy a WAF rule that inspects POST /rest/*/V1/guest-carts/*/items requests, base64-decodes the file_info content, and blocks payloads containing PHP tags (<?php, <?=) or executable extensions (.php, .phtml, .phar). This stops the upload step entirely. If your WAF cannot inspect base64-decoded JSON bodies, block the file_info parameter entirely on guest-cart endpoints. Deploy within hours given active exploitation.
3
CRITICAL 9.8→IGNORE 0.0
SEVERITY REDUCED
Apply APSB26-73 vendor patch — Install the appropriate 2.4.x-2026-jul security update for your version branch. This is the definitive fix — it adds option ID validation, option type gating, and file extension restrictions to the ImageContentValidator. Given active exploitation, treat this as an emergency patch — deploy within hours to days, not the standard noisgate CRITICAL remediation SLA of ≤90 days. Test in staging first but do not let QA cycles extend beyond 48 hours.
4
CRITICAL 9.8→CRITICAL 9.8
Hunt for existing compromise indicators — Search for .php files in pub/media/custom_options/quote/ and across all pub/media/ subdirectories. Look for accesson.php backdoors, files with GIF89a headers containing PHP code, and JavaScript injections in CMS blocks referencing deepveindrilling[.]com or similar exfiltration domains. Run Sansec eComscan or grep -rn '<?php' pub/media/ as an immediate triage step. If indicators are found, assume full store compromise including database credentials in app/etc/env.php.
What doesn't work
  • Rate limiting on the REST API — the entire attack is a single POST request followed by a single GET; rate limits have no effect on a one-shot exploit.
  • CAPTCHA or bot protection on checkout flows — the vulnerable endpoint is the guest-cart item addition API, which fires before any checkout CAPTCHA is presented.
  • Standard antivirus/malware scanning — polyglot files pass AV signature checks because they have valid GIF89a image headers; the PHP payload is only triggered by the web server's PHP interpreter.
  • Content-Type validation at the HTTP level — the upload is embedded as base64 inside a JSON body with Content-Type: application/json; the dangerous file type is only materialized server-side after decoding.
  • Magento Admin 2FA/MFA — the attack never touches the admin panel; it uses the unauthenticated storefront REST API.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationActive and widespread. Sansec Shield documented exploitation attempts against 79.5% of monitored stores by March 30, 2026. A campaign linked to deepveindrilling[.]com compromised 953+ stores with JS skimmers (SecurityWeek).
Proof-of-conceptPublic weaponized PoC. Python exploit by Abraxas Labs: abraxas/CVE-2026-48356, published September 26, 2026. Targets POST /V1/guest-carts/{cartId}/items with polyglot GIF89a+PHP payload. Also indexed on Sploitus.
EPSS17.9% probability (96.8th percentile) per current Feedly intelligence — significantly elevated from the initial 1.0% at disclosure, reflecting confirmed mass exploitation.
CISA KEVNot listed as of October 27, 2026. Meets all KEV inclusion criteria (active exploitation, vendor patch available, assigned CVE). Inclusion likely imminent given the 953-store campaign evidence.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N (vendor, 9.3). Disputed: the REST API attack path requires no user interaction (UI:N). With UI:N, the calculated score exceeds 9.8. Adobe's APSB26-73 bulletin separately lists this as 9.6.
Affected versionsAdobe Commerce 2.4.4–2.4.9 (all patch levels through -p18/-p17/-p15/-p10/-p5), Magento Open Source 2.4.6–2.4.9 (all patch levels), Commerce B2B 1.3.3–1.5.3, Adobe I/O Events for Commerce. Sansec states vulnerable code exists since the first Magento 2 release.
Fixed versionsAPSB26-73 (July 14, 2026): 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. The fix was first included in the 2.4.9-alpha3 pre-release branch.
Internet exposure~50,000 Adobe Commerce/Magento instances indexed on Shodan and FOFA. These are e-commerce storefronts — internet-facing by definition. Every unpatched instance is directly exploitable.
Disclosure timelineSansec discovered and named PolyShell; exploitation observed in the wild from March 2026. Adobe published APSB26-73 on July 14, 2026. Abraxas Labs published the PoC on September 26, 2026.
Researcher creditSansec Forensics Team (discovery, naming as PolyShell, in-the-wild tracking). Abraxas Labs (@abraxas_null, abraxaslabs.tech) published the weaponized PoC.

Sources.

  1. Sansec Research — PolyShell: unrestricted file upload in Magento
  2. Adobe Security Bulletin APSB26-73
  3. Abraxas Labs PoC — CVE-2026-48356 on GitHub
  4. SecurityWeek — 953 Online Stores Infected in Long-Running Campaign
  5. CIS Advisory — Multiple Vulnerabilities in Adobe Products
  6. SentinelOne Vulnerability Database — CVE-2026-48356
  7. Sploitus Exploit Entry — CVE-2026-48356 by Abraxas
  8. Feedly CVE Intelligence — CVE-2026-48356
05 · The Call

Final Verdict
= UNCHANGED to CRITICAL (9.8/10)

Why this verdict

  • Unauthenticated RCE with zero friction: The attack is a single POST to a default-enabled, public REST API endpoint. No authentication, no user interaction (despite the vendor CVSS claiming UI:R), no race conditions, no memory corruption — just a JSON body with a polyglot file. Attack complexity is effectively zero.
  • Active mass exploitation at scale: This is not a theoretical risk. Sansec documented 79.5% of monitored stores being targeted, and 953+ stores have been confirmed compromised with payment card skimmers. The attack campaign predates the patch by months.
  • Public weaponized PoC eliminates skill barrier: The Abraxas Labs Python PoC on GitHub automates the full chain from cart creation to shell upload. Any script kiddie with curl can reproduce this.
  • Role multiplier: Adobe Commerce and Magento are canonically internet-facing e-commerce platforms. 100% of installs occupy the high-value role by definition — they process payment card data (PCI DSS scope), store customer PII, and handle financial transactions. A successful exploit yields: (a) PCI cardholder data via database credentials in env.php, (b) customer PII at scale, (c) persistent JavaScript skimmer injection for ongoing card theft, (d) supply-chain impact on downstream customers. Blast radius is tenant-to-fleet scale — a single exploit compromises the entire store's data and customer base. This is not a workstation vuln with hypothetical server deployment; the server IS the product.
  • Vendor CVSS understates the attack: Adobe's vector includes UI:R, but the documented and observed attack path through the REST API requires no user interaction whatsoever. Correcting to UI:N with S:C pushes the base score to 10.0. Even conservatively, 9.8 is the floor.

Why not higher?

The reassessed score of 9.8 is already near the CVSS ceiling. A 10.0 would require Availability impact of High (A:H), which is not the primary impact here — the attack focuses on confidentiality (data theft) and integrity (webshell, skimmer injection) rather than denial of service. The scope-change designation and the absence of availability impact cap the theoretical maximum.

Why not lower?

Every downgrade factor fails to apply. The target is internet-facing by design (no network segmentation benefit). The API endpoint is enabled by default (disabling it breaks core checkout). No authentication is required. The PoC is public and weaponized. Mass exploitation is confirmed and ongoing. There is no deployment scenario where an Adobe Commerce instance is not a high-value target — it exists to process payments and hold customer data. The only friction point (WAF blocking polyglot payloads in base64-encoded JSON) requires non-default, highly specific rules that the vast majority of deployments lack.

06 · Verification

Crowdsourced verification payload.

Run this script on the Magento application host as any user with read access to the Magento installation directory. Invoke with: bash check_polyshell.sh /var/www/magento (replace with your Magento root path). No elevated privileges required — read-only filesystem checks.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-48356 (PolyShell) Vulnerability Check
# Checks Adobe Commerce / Magento Open Source for APSB26-73 patch status
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -uo pipefail

MAGENTO_ROOT="${1:-}"

if [[ -z "$MAGENTO_ROOT" ]]; then
  echo "[!] Usage: $0 /path/to/magento/root"
  echo "Result: UNKNOWN"
  exit 2
fi

if [[ ! -d "$MAGENTO_ROOT/vendor/magento" ]]; then
  echo "[!] $MAGENTO_ROOT does not appear to be a Magento installation"
  echo "Result: UNKNOWN"
  exit 2
fi

# Detect version
VERSION=""
if [[ -f "$MAGENTO_ROOT/composer.lock" ]]; then
  VERSION=$(python3 -c "
import json, sys
with open('$MAGENTO_ROOT/composer.lock') as f:
    data = json.load(f)
for p in data.get('packages', []):
    if p['name'] in ('magento/product-community-edition','magento/product-enterprise-edition'):
        print(p['version']); sys.exit(0)
" 2>/dev/null || true)
fi
if [[ -z "$VERSION" ]] && command -v php &>/dev/null && [[ -f "$MAGENTO_ROOT/bin/magento" ]]; then
  VERSION=$(php "$MAGENTO_ROOT/bin/magento" --version 2>/dev/null | grep -oP '[\d]+\.[\d]+\.[\d]+(-p\d+)?' || true)
fi
echo "[*] Detected version: ${VERSION:-unknown}"

# Check 1: Look for the APSB26-73 patch fix in ImageContentValidator
VALIDATOR="$MAGENTO_ROOT/vendor/magento/framework/Api/ImageContentValidator.php"
FIX_FOUND=false
if [[ -f "$VALIDATOR" ]]; then
  # The patch adds explicit extension blocking for php/phtml/phar
  if grep -qE 'php|phtml|phar' "$VALIDATOR" 2>/dev/null && grep -qE 'forbidden|blocklist|disallowed.*extension' "$VALIDATOR" 2>/dev/null; then
    echo "[+] ImageContentValidator contains extension restriction (patch indicator)"
    FIX_FOUND=true
  else
    echo "[-] ImageContentValidator lacks extension restriction"
  fi
else
  echo "[?] ImageContentValidator not found at expected path"
fi

# Check 2: Look for option type gating in quote item handling
PROCESSOR="$MAGENTO_ROOT/vendor/magento/module-quote/Model/Quote/Item/Processor.php"
if [[ -f "$PROCESSOR" ]]; then
  if grep -qE 'validateOptionType|isFileOption|optionTypeCheck' "$PROCESSOR" 2>/dev/null; then
    echo "[+] Quote Item Processor contains option type gating (patch indicator)"
    FIX_FOUND=true
  else
    echo "[-] Quote Item Processor lacks option type gating"
  fi
fi

# Check 3: Composer lock for July 2026 security release
if [[ -f "$MAGENTO_ROOT/composer.lock" ]]; then
  if grep -q '2026-jul\|2026\.jul' "$MAGENTO_ROOT/composer.lock" 2>/dev/null; then
    echo "[+] composer.lock references 2026-jul security release"
    FIX_FOUND=true
  fi
fi

# Check 4: Look for existing compromise indicators
echo ""
echo "[*] Scanning for compromise indicators..."
SHELLS_FOUND=0
if [[ -d "$MAGENTO_ROOT/pub/media/custom_options" ]]; then
  SHELLS_FOUND=$(find "$MAGENTO_ROOT/pub/media/custom_options" -name '*.php' -o -name '*.phtml' -o -name '*.phar' 2>/dev/null | wc -l)
  if [[ $SHELLS_FOUND -gt 0 ]]; then
    echo "[!!] COMPROMISE INDICATOR: Found $SHELLS_FOUND PHP files in pub/media/custom_options/"
    find "$MAGENTO_ROOT/pub/media/custom_options" -name '*.php' -o -name '*.phtml' -o -name '*.phar' 2>/dev/null
  fi
fi
BACKDOOR=$(find "$MAGENTO_ROOT/pub" -name 'accesson.php' 2>/dev/null | head -5)
if [[ -n "$BACKDOOR" ]]; then
  echo "[!!] COMPROMISE INDICATOR: accesson.php backdoor found:"
  echo "$BACKDOOR"
fi

# Check 5: Is PHP execution disabled in pub/media? (partial mitigation)
HTACCESS="$MAGENTO_ROOT/pub/media/.htaccess"
PHP_DISABLED=false
if [[ -f "$HTACCESS" ]]; then
  if grep -qi 'php_flag.*engine.*off\|RemoveHandler.*\.php\|deny from all' "$HTACCESS" 2>/dev/null; then
    echo "[+] PHP execution appears disabled in pub/media/ (.htaccess)"
    PHP_DISABLED=true
  fi
fi

echo ""
# Final verdict
if $FIX_FOUND; then
  echo "========================================"
  echo "Result: PATCHED"
  echo "========================================"
  exit 0
else
  echo "========================================"
  if [[ $SHELLS_FOUND -gt 0 ]]; then
    echo "[!!] ACTIVE COMPROMISE DETECTED"
  fi
  if $PHP_DISABLED; then
    echo "[~] Partial mitigation in place (PHP disabled in media dir)"
  fi
  echo "Result: VULNERABLE"
  echo "CVE-2026-48356 (PolyShell) - APSB26-73 patch NOT detected"
  echo "========================================"
  exit 1
fi