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.
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
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 amysql.phpdropper) 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
How to check
Confirm the version and whether SUPEE-11346 is present, then look for the persistence artifacts.
# 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
# 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.
- 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.
- 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-orderprotect_code, CVSS 7.5) fixed in 19.5.1/20.1.1. Migration is largely composer-driven and preserves the extension architecture.
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.