github OpenMage/magento-lts v20.18.2
v20.18.2 🌈

latest releases: v21.0.0-beta3, v20.19.0
4 hours ago

Security

v20.18.2 is a security-only patch release on top of v20.18.0. It fixes 31 security issues: 16 are published with CVE identifiers and 15 as GitHub Security Advisories only. Upgrade as soon as possible. Three further advisories published today (GHSA-5rg7-22cv-c9q6, GHSA-2jfg-wx75-5cc8 and GHSA-fqq6-76qg-2r96) need behaviour or schema changes too large for a patch release; they are fixed in v20.19.0 only. The 21.x pre-release line will be fixed in v21.0.0-beta3.

Why there is no v20.18.1. An automatically generated release draft named "v20.18.1" sat on the Releases page for months. It was never tagged or released, and its contents were feature work, which now ships as v20.19.0. We skipped the 20.18.1 number deliberately, so nobody confuses the security patch with that old draft. v20.18.2 is the first patch release after v20.18.0.

Scores are CVSS 3.1. Where a vulnerable feature ships disabled, the advisory says so and gives the score for stores that have it enabled.

Advisories with a CVE

Advisory Issue Severity CVE Fixed in
GHSA-grrq-9gq2-vm55 CSRF in OAuth authorization grants persistent admin or customer REST API tokens Critical 9.0 requested 20.18.2, 20.19.0
GHSA-4fxg-469f-r6fc Protected-extension blocklist omits phar/php8/phps, enabling guest file-upload RCE High 8.1 requested 20.18.2, 20.19.0
GHSA-7j66-6mw7-rgfx Predictable customer confirmation key and password-reset tokens allow account takeover High 8.1 requested 20.18.2, 20.19.0
GHSA-j9c5-pcvx-jx9x Stored XSS in RSS feeds served as text/html lets a guest run script in an administrator's browser High 8.0 (9.3 with the review feed enabled) requested 20.18.2, 20.19.0
GHSA-mffc-h5pf-6f42 OAuth callback URL allowlist bypass leaks admin or customer OAuth verifier High 7.7 requested 20.18.2, 20.19.0
GHSA-3w23-mpwf-q79h Authenticated RCE via unsafe unserialize() of CSP configuration High 7.2 requested 20.18.2, 20.19.0
GHSA-57qq-p497-7grq Authenticated RCE via absolute-path file write in product image APIs High 7.2 requested 20.18.2, 20.19.0
GHSA-v2qw-3rm9-qx3p Default XML namespace bypasses the layout update validator (file read/write by a catalog-only admin) High 7.2 requested 20.18.2, 20.19.0
GHSA-8v83-5w2r-ghrp Authenticated RCE via unsafe unserialize() in Varien_Convert_Parser_Serialize High 7.2 requested 20.18.2, 20.19.0
GHSA-989j-pjxc-9hgp Dataflow HTTP cURL adapter reads local files and internal URLs (SSRF, local file disclosure) Medium 6.8 requested 20.18.2, 20.19.0
GHSA-68jq-pfh7-9pjx SSRF in downloadable product URL links and samples Medium 6.8 requested 20.18.2*, 20.19.0
GHSA-75mq-cvpr-g7wq Reflected XSS via unescaped session messages Medium 6.1 requested 20.18.2, 20.19.0
GHSA-w5fm-m59p-w9q5 Cross-customer custom-option file disclosure Medium 5.9 requested 20.18.2, 20.19.0
GHSA-2p72-3v6m-9p2h Custom-option file download path traversal to arbitrary file read Medium 5.3 requested 20.18.2, 20.19.0
GHSA-3hh8-xg45-mwrr Forgeable order-status RSS URL key exposes other customers' orders (RSS off by default) Medium 5.3 requested 20.18.2, 20.19.0
GHSA-23v7-qrrp-4m96 SOAP API trusts the Host header for its WSDL URL (blind SSRF, WSDL injection) Medium 5.3 requested 20.18.2, 20.19.0

* In 20.18.2, downloadable links on private networks are still allowed by default, to avoid breaking existing stores. See Behaviour changes.

Advisories without a CVE

These are published so you can track them. Each one either needs an administrator account and crosses no authority boundary, or has low impact.

Advisory Issue Severity Fixed in
GHSA-p87f-mr5h-8ww9 Unsafe unserialize() without class restriction in recurring profile and date option Medium 6.6 20.18.2, 20.19.0
GHSA-m858-x59w-rmp5 Admin-to-admin stored XSS (Dataflow status, tax rate title, OAuth consumer name, PayPal certificate field) Medium 6.1 20.18.2, 20.19.0
GHSA-rrhg-c635-fmrm API access survives user deactivation (SOAP/XML-RPC sessions and REST OAuth tokens) Medium 5.9 20.18.2, 20.19.0
GHSA-rmw8-7h79-p386 Free payment method accepted on orders with a non-zero total (cart API) Medium 4.4 (5.9 on API/headless checkouts) 20.18.2, 20.19.0
GHSA-rqc2-p2h7-6hw9 Guest order lookup rate limiter never throttles a request Medium 5.3 20.18.2, 20.19.0
GHSA-94p5-6j66-c9j6 Email template getConfig directive discloses encrypted configuration secrets to restricted admins Medium 4.9 20.18.2, 20.19.0
GHSA-v7mx-rv47-452m Guest SVG upload via product custom option runs script in the store origin Medium 4.7 20.18.2, 20.19.0
GHSA-28hq-mq6h-fh2x Stored XSS via Dataflow batch import row errors Medium 4.7 20.18.2, 20.19.0
GHSA-6pvw-8mv9-r8vr Reflected XSS on error pages via unescaped SCRIPT_NAME-derived URLs Medium 4.7 20.18.2, 20.19.0
GHSA-9783-jfj5-gfpv Missing CSRF protection on customer account actions Medium 4.3 20.18.2, 20.19.0
GHSA-wmwx-442r-jc88 Order-status RSS feed discloses internal invoice, shipment and credit-memo comments Medium 4.3 20.18.2, 20.19.0
GHSA-7vww-whgh-98cf WYSIWYG image directive endpoint allows SSRF, media path traversal and path disclosure Medium 4.1 20.18.2, 20.19.0
GHSA-wgf8-gh63-gfqf Insufficient granular ACL enforcement in admin controllers Low 3.8 20.18.2, 20.19.0
GHSA-hfqq-c3qm-38x8 Admin-planted stored XSS via product name (storefront MSRP popup, Qty Increments notice) Low 3.5 20.18.2, 20.19.0
GHSA-w949-chmj-mx9m Path traversal in WYSIWYG thumbnail endpoint reads images outside media/wysiwyg Low 2.7 20.18.2, 20.19.0

Hardening

These are not vulnerabilities in a default install, but are fixed as defence in depth. Thank you to everyone who reported them.

  • Mage_Archive_Tar now confines extracted entries to the target directory, skips symlinks that escape it, and drops setuid/setgid/sticky bits. No core code calls it. Thanks @lichoin.
  • The three phar:// guards are case-insensitive and catch nested stream wrappers. The phar wrapper is already unregistered at bootstrap. Thanks subhashdasyam (HackerOne) and Bassem Tarek (@1xNANO).
  • Dataflow profiles refuse action and container types that are not Dataflow containers before constructing them, and stop with an error when an action names a method the container lacks. Thanks @hariprasanth9317-tech.
  • Gift message To/From fields escape the customer's default name (self-XSS). Thanks @0x5t4l1n (w4nn4d13 on HackerOne).
  • Varien_Simplexml_Config_Cache_File unserializes its .stat file with allowed_classes => false and treats a tampered file as a stale cache.
  • A regression test keeps the HTMLPurifier pass of the MaliciousCode filter in place against unclosed-tag and slash-separated event-handler shapes. Thanks @Judx.

Behaviour changes and upgrade notes

Review these before you upgrade. Most need no action unless you run a custom theme, an extension that overrides the named templates or classes, or a restricted admin role.

Server configuration

  • nginx: deny /media/custom_options/. Add location /media/custom_options/ { deny all; } next to your existing rules for /media/customer/, /media/downloadable/ and /media/import/. The upgrade does not touch your server config. Apache users get a new media/custom_options/.htaccess, so make sure AllowOverride lets it take effect.
  • Rate limiter behind a proxy or CDN. After a failed Orders and Returns lookup, the client IP is now refused for system/rate_limit/timeframe seconds (default 30). If you run behind a load balancer, reverse proxy or CDN, list the real-client-IP header under global/remote_addr_headers in app/etc/local.xml. Otherwise all visitors share one IP, and one failed lookup blocks everyone. Set system/rate_limit/active to 0 to switch the limiter off.

Configuration to review

  • Downloadable products: private networks. Link and sample URLs that resolve to loopback, link-local, cloud-metadata or reserved addresses stop working in both releases. In 20.19.0, private-network hosts (10/8, 172.16/12, 192.168/16, 100.64/10, fc00::/7) are also refused by default. In 20.18.2 they are still allowed by default. Go to System → Configuration → Catalog → Catalog → Downloadable Product Options, set Allow Link URLs on Private Networks to No, and list hosts you trust under Trusted Link URL Prefixes. A new hourly cron job, downloadable_link_url_audit, and admin inbox messages list affected links.
  • Upload extensions. php8, phar and phps are refused wherever the protected-extension list applies. The protected list now has a fixed minimum (PHP variants, phtml, pht, phar, phps, pl, py, cgi, sh, asp, aspx, jsp, htaccess, shtml) that applies even if you saved your own general/file/protected_extensions; you can add extensions but not remove these. A File custom option with no "Allowed File Extensions" list refuses htm, html, svg, svgz, xhtml, xht, xml, xsl and xslt uploads; list a type on the option to accept it, and keep media/custom_options/ off the web if you do.
  • Dataflow URL fetch. An invalid or non-http(s) uri in a cURL adapter now fails the profile. Hosts that resolve to loopback, link-local (cloud metadata) or other special-purpose addresses are refused, and redirects are not followed, so point profiles at the final URL. Private-network hosts stay allowed unless you set Allow Private Network Addresses to No. Hosts listed under System → Configuration → System → Dataflow URL Fetch → Allowed URL Prefixes skip the address check. If PHP runs with an http_proxy environment variable, the proxy resolves host names; restrict the proxy's destinations.
  • Email templates. store.getConfig() in any letter case returns empty for encrypted settings and their parent nodes. If restricted admins have held System → Transactional Emails, consider rotating payment and carrier credentials.

Admin roles (granular ACL)

  • Editing an order address now requires Sales → Orders → Actions → Edit.
  • Editing an existing order requires Edit, not Create. Create-only roles lose this; Edit-only roles regain it, which fixes the regression in #2342.
  • Each of these now needs its own permission: mass Cancel/Hold/Unhold, Void, report exports and detail pages, All Tags, REST role and REST attribute management, table-rate export, USPS tools, and tax rate import/export.
  • Print All leaves out credit memos for roles without credit-memo access.
  • Some narrowly scoped roles gain access they were wrongly denied: Bestsellers export, tax import, and the REST role Add button. Review roles that are not full-access after upgrading.

Themes and links (CSRF)

  • Customer-account actions need a form key. These actions return 404 without one: billing agreement cancel, reorder (customer and guest), recurring profile cancel/suspend/activate/update, and customer OAuth token revoke/delete. Themes that use the stock block URL getters keep working. Custom code that builds these URLs itself must add form_key or POST with the formkey block. In 20.19.0 the base and rwd templates use POST forms; 20.18.2 changes no templates.
  • OAuth authorization buttons. The confirm actions require POST plus the form key, and a GET returns 404. If you override oauth/authorize/button.phtml or button-simple.phtml, submit with method="post" and include the formkey block.
  • OAuth callbacks. A consumer with a registered callback URL must use the same scheme, host and port, under the registered path.

Feeds

  • RSS feed URLs are re-issued. Every order-status feed URL issued before the upgrade stops working, and customers get new signed links on their order page. This only matters if order-status RSS is enabled, which it isn't by default. All RSS responses are now text/xml with nosniff, names in feed entries are HTML-escaped, and hidden invoice, shipment and credit-memo comments no longer appear in the customer order-status feed.

Other

  • Layout updates are checked more strictly. Updates that contain xmlns, call setTemplate/setDataUsingMethod with a different letter case or a Class:: prefix, name a disallowed block through class or a module/name alias, or put .. in a template argument are rejected. CMS pages and widget instances are validated only on save, so after upgrading, search cms_page.layout_update_xml, cms_page.custom_layout_update_xml and core_layout_update.xml for xmlns (and for unusual method= values or ..) and remove anything you did not put there. Product and category updates are dropped at render time.
  • Session messages are purified. Flash messages on the storefront and in the admin keep only simple markup (a b br em i strong span p ul ol li and similar); other tags appear as text, and class, style and target attributes are removed. Check extensions that put buttons, forms, images or scripts in messages. The base core/messages.phtml template now prints the same purified output.
  • API access after deactivation. Deactivating a SOAP/XML-RPC API user or changing its API key now ends its open sessions immediately. REST requests with an OAuth token of a deleted or inactive admin user get HTTP 401, and deactivating an admin user revokes its OAuth tokens; after reactivating the account, re-enable them under System → Web Services → REST - OAuth Authorized Tokens.
  • Customer confirmation keys. Accounts that registered before the upgrade and are still unconfirmed keep their old key. Consider removing stale unconfirmed accounts.
  • Checkout. The Zero Subtotal Checkout method refuses an order whose grand total is not zero.
  • Free-shipping coupons. A rule or coupon that only grants free shipping now counts towards its Uses per Coupon and Uses per Customer limits. Before, those limits never applied to it, because the order carried no discount amount (#4757, fixed by #5554). Uses from before the upgrade were not recorded.
  • Product image APIs (REST/SOAP). Image file names are reduced to [A-Za-z0-9_.-], so spaces and slashes become underscores.
  • Custom-option file downloads return 404 when the stored path lies outside media/custom_options/, or when the file no longer matches its key. An admin following a wishlist file link from the customer edit page also gets 404.
  • SOAP WSDL. The WSDL and soap:address use the configured store host unless the request's Host matches a configured store base URL.
  • Logging. v20.18.0 shipped with dev/log/max_level defaulting to emergency-only, so warnings and exceptions (including the refusals these fixes log) were dropped. The default is Debug again, as in earlier releases (#5790); expect system.log and exception.log to grow again.
  • Dependencies. Locked dependencies flagged by composer audit are updated within the existing constraints (Guzzle, Symfony components, phpseclib, HTMLPurifier 4.19.1, TinyMCE 8.5.1). composer.json is unchanged.
  • Admin error output. A failed Dataflow profile run shows a generic error and logs the exception to var/log/exception.log.
  • Template overrides. If your theme overrides any of these templates, apply the same escaping: tax/rate/title.phtml, sales/order/totals/tax.phtml (admin), oauth/authorize/form/login*.phtml, system/convert/profile/process.phtml, the MSRP price templates, and cataloginventory/qtyincrements.phtml.

Thanks

We thank every researcher who reported these issues through GitHub and HackerOne. Each advisory names its reporters.

Changes

Security fixes only, on top of v20.18.0, plus:

  • fix: default dev/log/max_level drops all levels except emergency (#5790)
  • [SalesRule] count coupon usage for free-shipping-only rules (#5554, fixes #4757)
  • Harden login credential handling against non-string POST input (#5723)
  • Locked dependency updates flagged by composer audit

Full Changelog: v20.18.0...v20.18.2

Don't miss a new magento-lts release

NewReleases is sending notifications on new releases.