Skip to content
Scanner online 200 stores scanned
magekwik scanner Magekwik Scanner home
Sign in
critical CVE-2020-9664 CVSS 9.8

Magento 1 after end of life: SUPEE-11346, the CVE-2020-9664 cliff, and the OpenMage bridge

Kishore Adobe Commerce Certified Professional 6 min read

Covers events from 22 July 2020.

Critical CVEs CVE-2020-9664 CVSS 9.8 scan.magekwik.com

Magento 1 hit end of life on 30 June 2020 after SUPEE-11346. Every flaw since, starting with the 9.8-rated CVE-2020-9664, has no vendor patch. What Cardbleed exploited, how to check a store, and why OpenMage LTS is the realistic bridge.

What it is

Magento 1 (Community and Commerce) reached end of life on 30 June 2020. Adobe shipped one final security patch, SUPEE-11346, on 22 June 2020 and then stopped. Every vulnerability disclosed against the 1.x codebase since that date has no vendor fix. The install base did not shrink on the EOL date. Tens of thousands of storefronts still serve checkout on unpatched 1.9.x/1.14.x today, which makes "runs Magento 1" a reliable proxy for "has an unremediated remote-code-execution path."

SUPEE-11346 itself closed two issues that define the risk profile of an abandoned platform: CVE-2020-9664 (PHP object injection leading to arbitrary code execution) and CVE-2020-9665 (stored XSS). The first is the one that matters.

The cliff

NVD scores CVE-2020-9664 at CVSS 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H): network-reachable, low-complexity code execution with no privileges required. Note a known NVD-vs-vendor discrepancy: Adobe's APSB20-41 bulletin categorised it as exploitable by an authenticated admin, whereas NVD's vector scores it PR:N (unauthenticated). Either way, on an unpatched Magento 1 store there will never be an official fix. The vendor lifecycle ended before most operators applied the last patch. It affects 1.14.4.5 / 1.9.4.5 and earlier.

Root cause

The structural problem is not a single bug; it is a frozen dependency tree. Magento 1 ships a bundled, forked copy of Zend Framework 1 (itself EOL since 2016), Prototype.js, and a large surface of admin controllers (downloader/, Magento Connect, RSS, import/export) that were written before modern deserialization and SSRF hardening. PHP object injection flaws like CVE-2020-9664 exist because untrusted input reaches unserialize() against classes whose __destruct()/__wakeup() methods perform filesystem or database side effects. That is the classic POP-chain gadget pattern.

Once the codebase is EOL, each newly found gadget or auth-bypass is permanent. Nobody backports a fix, re-scores it or publishes an advisory. The only parties writing fixes are the community and the attackers, and the attackers move first because a version string on a dead platform is a guaranteed, non-expiring lead.

How attackers abuse it

The pattern is consistent across the Magento 1 skimming campaigns. An unauthenticated RCE or admin-auth bypass gives a foothold; the attacker then uses legitimate platform machinery to persist and to place a card skimmer on the checkout DOM.

  • Reach an object-injection or upload sink to execute code without credentials.
  • Use the Magento Connect / downloader/ subsystem to install a PHP backdoor (Sansec observed a mysql.php dropper) so access survives the initial patchless entry point being closed.
  • Inject JavaScript into a bundled asset such as prototype.js, or into the CMS/layout, so the skimmer loads on every payment page and exfiltrates PAN + CVV to an attacker host.

Because the skimmer rides an existing, trusted script rather than an external <script> tag, naive CSP allowlists and manual "view source" checks miss it.

Who got hit / real examples

In the weekend of 11-13 September 2020, ten weeks after EOL, Sansec documented the Cardbleed campaign, the largest automated Magecart operation recorded at the time. It infected roughly 1,900 distinct Magento 1 stores in the first days and climbed to 2,806, about 3% of the entire Magento 1 install base. The intrusions abused the /downloader endpoint and Magento Connect to drop mysql.php and patch prototype.js with skimmer code. Sansec linked the timing to a Magento 1 RCE zero-day advertised for sale by an actor using the handle z3r0day shortly before the campaign.

Not a one-off

Follow-on reporting counted 2,000+ then 2,800+ compromised shops within weeks. The common denominator was not a specific merchant mistake. It was running the EOL platform at all. EOL turned a routine skimming operation into a mass, indiscriminate sweep.

How to check

Confirm the version and whether SUPEE-11346 is present, then look for the persistence artifacts.

Version and last-patch check (read-only)
# Version string — load Mage.php, then ask it (getVersion() is self-contained)
php -r "require 'app/Mage.php'; echo Mage::getVersion(), PHP_EOL;"
# or read the version parts straight from the source:
grep -A8 "getVersionInfo" app/Mage.php | grep -E "major|minor|patch|revision"

# Was the final patch applied? SUPEE-11346 touches these files
grep -l "SUPEE-11346" app/etc/applied.patches.list 2>/dev/null
Skimmer / backdoor triage
# Unexpected droppers in webroot
find . -name "mysql.php" -o -name "*.php" -newermt "2020-06-30" \
  | xargs grep -l "eval\|base64_decode\|assert(" 2>/dev/null

# Tampered bundled asset — compare against a pristine copy
git diff --stat js/prototype/prototype.js 2>/dev/null
grep -RiE "onestepcheckout|guaranteed|atob\(|fromCharCode" skin/ js/ | head

Also review admin user list, secret admin path, and outbound connections from the checkout template. An externally reachable downloader/ is itself a finding.

How to fix it

There is no supported patch stream for Magento 1. Two defensible paths exist; picking neither is the failure mode.

  1. Migrate to Adobe Commerce / Magento 2.4.x. The correct long-term answer, but a project, not a patch. It does not help the store that is exposed this week.
  2. Move to OpenMage LTS. The community fork of Magento 1 Community Edition, actively maintained on the 19.x/20.x lines, is the pragmatic bridge. It backports fixes the abandoned codebase never received, for example custom-layout RCE hardening in 19.4.22/20.0.19, arbitrary-upload fixes in 19.4.15/20.0.13, and CVE-2023-41879 (weak 6-hex guest-order protect_code, CVSS 7.5) fixed in 19.5.1/20.1.1. Migration is largely composer-driven and preserves the extension architecture.
Adopt the maintained fork
composer require openmage/magento-lts:^20.1
# then diff local core mods against upstream, re-run compile, retest checkout

Whichever path you choose, treat any current Magento 1 install as breached-until-proven-clean: remove the downloader/ subsystem from the public webroot, rotate admin credentials and encryption keys, verify integrity of all bundled JS, and confirm no unknown admin users. A clean scan of a dead platform describes that moment only. The only durable remediation is getting off the EOL codebase.

References & sources

Primary sources: advisories, vendor research and the CVE record. Verify against these rather than against us.

  1. Adobe Security Bulletin APSB20-41 (SUPEE-11346)
  2. NVD: CVE-2020-9664 (CVSS 9.8)
  3. Sansec: Cardbleed: 3% of Magento 1 install base hacked
  4. The Hacker News: 2,800+ outdated Magento shops hit by skimmers
  5. OpenMage LTS: community-maintained Magento 1 fork
Critical CVEs CVE-2015-1397 CVSS 6.5
critical Critical CVEs

Shoplift (CVE-2015-1397): the Magento 1 SQL injection that was weaponised in 24 hours

CVE-2015-1397 is the SQL injection at the centre of the Magento 1 "Shoplift" chain: an unauthenticated grid-export flaw that let attackers write admin accounts straight into the database. Patched by SUPEE-5344 in February 2015, it was mass-exploited within a day of disclosure. The mechanism, the indicators of compromise, and the fix.

6 min read

← All security posts