Skip to content

3.5.0

Latest

Choose a tag to compare

@marcelmtz marcelmtz released this 08 Sep 22:00
· 0 commits to main since this release

Released: 2026-09-08
Upstream: Magento Open Source 2.4.9

Mage-OS 3.5.0 is an emergency security release. It ports Adobe's VULN-39341 hotfix for StyleSmuggler (CVE-2026-75650, CVSS 10.0, APSB26-146) — an unauthenticated remote code execution flaw that has been exploited in the wild since 4 September 2026 — along with a layer of defense-in-depth hardening around the same attack surface, Adobe's September isolated patch 249-2026-09-001-CE (APSB26-138), and four bug fixes.

Every Mage-OS 3.x installation should upgrade immediately.

composer require mage-os/product-community-edition 3.5.0 --no-update
composer update

Upgrading is not sufficient on its own. Stores were exploitable for three days before a patch existed, so read the Upgrade notes below — they cover compromise assessment and credential rotation, both of which Adobe and Sansec consider part of the remediation, not optional follow-up.

There are no dependency additions, removals or constraint changes in this release, and no changes to magento2-base or project-community-edition beyond version bumps.

For the announcement write-up, see Mage-OS 3.5.0 – Emergency Security Release on mage-os.org.


Security

StyleSmuggler — CVE-2026-75650 (APSB26-146)

Adobe published this out of band on 7 September 2026 after Sansec reported active exploitation. It is an unauthenticated remote code execution vulnerability affecting all Magento Open Source and Adobe Commerce versions from 2.4.4 through 2.4.9, scored CVSS 10.0. Adobe ships it as a vendor/-level hotfix rather than a tagged Magento release, so there is no new upstream version — 3.5.0 still tracks Magento Open Source 2.4.9. Mage-OS has mapped the patch onto the source tree so you receive it through a normal Composer upgrade.

The exploit chain is two-stage: an attacker first plants PHP into a file the application will later read (typically a failure report), then triggers evaluation of that content through the transactional email template pipeline. No admin session and no user interaction are required. Sansec observed attacks beginning 4 September 2026, with multiple unrelated threat actors and rapidly evolving payloads; in some cases two distinct groups placed different backdoors on the same store.

What the hotfix changes (#334):

  • Backend\Model\Widget\Grid\Row\UrlGeneratorFactory validates that the requested generator class implements GeneratorInterface before instantiation, so a gadget class's constructor arguments are never resolved.
  • Email and Newsletter admin preview blocks (_toHtml()) now require the matching ACL resource — Magento_Email::template, Magento_Newsletter::template, Magento_Newsletter::queue — before rendering a request-driven preview.
  • Email\Model\AbstractTemplate string-coerces setTemplateText() and setTemplateStyles(), so structured data cannot reach the template filter.
  • Framework\View\Element\BlockFactory resolves the DI preference and validates the resulting type against BlockInterface before instantiation; Layout\Generator\Block catches the resulting LogicException.
  • Framework\Webapi\ErrorProcessor and pub/errors/processor.php prefix generated error reports with a <?php exit; ?> execution guard and neutralize PHP open tags in report data. The guard is stripped again when a report is read back through the normal reporting UI.

Defense in depth

Because StyleSmuggler was exploited before it was patched, and because the underlying pattern — attacker-influenced content reaching a template evaluation path — has produced repeated findings in this area, 3.5.0 adds three hardening layers on top of Adobe's fix (#335). This is additional protection specific to Mage-OS; it is not part of Adobe's patch.

  • Block directive policy. The {{block}} directive in the email template filter now checks the requested class against a restricted-class policy, and re-checks the class actually instantiated. Directive parameter handling in blockDirective() and layoutDirective() was tightened. The deny list is configurable through DI (Magento\Email\Model\Template\Filter\BlockDirectivePolicy) for stores that need to adjust it.
  • Directive output neutralization. Framework\Filter\Template now neutralizes resolved directive output so it cannot be re-parsed by a later filtering pass — closing the class of bug where a directive's result is treated as a new template. Explicitly deferred directives are signed and pass through unchanged. The behavior can be disabled through DI if it interferes with a custom filter chain.
  • Template include-path validation. A new Framework\Filesystem\SecurePathValidator anchors template include paths to the application root, and is applied in View\Result\Page, View\TemplateEngine\Php and the setup DI scanners.

September isolated patch 249-2026-09-001-CE (APSB26-138)

Adobe's September scheduled bulletin, APSB26-138, shipped as an isolated patch. It includes CVE-2026-77111 — incorrect authorization leading to a security feature bypass, CVSS 8.7 (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H). See APSB26-138 for the full issue list, CVE identifiers and severity ratings.

Seven independent fixes, ported verbatim with vendor paths mapped to repo paths (#337):

  • Backup rollback controller — the ACL check ran inside execute() and called _forward('denied') without returning, so execution continued past the denial. It is now ADMIN_RESOURCE = 'Magento_Backup::rollback', enforced by the framework before dispatch.
  • CustomerGraphQl\Model\Context\AddUserInfoToContext — resets the context user id to 0 when a customer-type token fails the isCustomer check, and validates website scope against the store named in the Store header rather than the default store.
  • ImportExport export-file delete controller — path traversal and arbitrary file deletion. The requested path is normalized with getRealPathSafety(), and only files that exist and pass FileInfo::isExportFile() are deleted.
  • InstantPurchase option loading — IDOR. Shipping and billing address ids are verified to belong to the current customer.
  • PayPal Express _initCheckout() — the quote id is stored in the checkout session only when the quote is the session quote or is owned by the logged-in customer.
  • Admin order create scripts.js — the VAT number is escaped before interpolation into validation messages (XSS).
  • Framework\Escaper::escapeXssInUrl() — decodes HTML entities to a fixed point (capped at 10 iterations, empty string on overflow) instead of a single html_entity_decode() pass, closing double-encoding bypasses.

Bug fixes

  • Weee item price renderer no longer divides by zero when qty_ordered is 0. (#329 — Tu Van)
  • Persistent quote cleanup cron no longer loops indefinitely, and its batches are bounded. Previously the cron could spin without making progress and process unbounded result sets. (#333 — Tu Van)
  • On-the-fly image regeneration works for images with no media gallery row. It previously failed silently, leaving the resized image missing with no error. (#336 — emetik)
  • MockCreationTrait::createPartialMockWithReflection() no longer fatals on interfaces that declare more abstract methods than the test requested. Test infrastructure only; no runtime effect. (#332 — Lucas van Staden)

Bundled add-on updates

  • mage-os/module-automatic-translation 2.2.1 → 2.3.1. url_key values are now generated with Magento's translit filter for non-Latin target languages, and the OpenAI translator was moved to the Chat Completions API. Stores using the OpenAI translator should verify translation still works after upgrading, since this changes the outbound API call.
  • elgentos/magento2-varnish-extended 2.0.6 → 2.0.7. xkey purge tags are normalized to whitespace-separated form for purge compatibility, plus grace debugging in vcl_recv. If you maintain custom VCL that parses xkey tags, review it.

All other bundled add-ons are unchanged from 3.4.0: module-page-builder-template-import-export 1.9.0, module-admin-activity-log 2.0.2, module-rma 2.4.1, module-meta-robots-tag 1.2.1, module-theme-optimization 2.3.0, module-page-builder-widget 1.5.0, module-inventory-reservations-grid 1.0.5, theme-adminhtml-m137 1.3.4, swissup/module-ignition 1.3.2, aligent/magento2-pci-4-compatibility 1.4.2, creatuity/magento2-interceptors 1.3.8 and element119/module-custom-admin-logo 2.0.0.


Upgrade notes

Mage-OS 3.5.0 tracks the same upstream release as 3.4.0 (Magento Open Source 2.4.9). No dependencies were added, removed or re-constrained, and extra.magento_version is unchanged.

Patching is not the whole remediation

StyleSmuggler was exploited in the wild for three days before Adobe published a fix, against stores that were fully patched at the time. If your store was internet-reachable during that window, treat it as potentially compromised until you have evidence otherwise:

  1. Upgrade to 3.5.0.
  2. Scan for implants. Attackers deployed backdoors, and in observed cases more than one, from unrelated groups, on the same store. Sansec's StyleSmuggler write-up documents the observed payloads and what to look for — start there. Check for unexpected files under pub/, var/report/, and modified files in app/code/. Mage-OS runs Sansec eComscan in CI; it is also available for merchant use.
  3. Rotate the encryption key and every credential it protected — admin passwords, API tokens, integration tokens, payment credentials and SSH keys — at their source. Rotating the encryption key alone does not invalidate anything an attacker has already read. This is the step most likely to be skipped and the one that matters most.

Rotating the encryption key re-encrypts stored values; it does not change the values themselves at the payment gateway, the API provider or the remote host. Those must be reissued where they were created.

Behavior changes to be aware of

Email template previews now require explicit ACL resources. An admin role with access to the email or newsletter template grids but without Magento_Email::template, Magento_Newsletter::template or Magento_Newsletter::queue will see an empty preview instead of rendered output. The resources already exist in earlier versions; they were simply not enforced on the preview blocks. Review admin roles and grant them explicitly where they are legitimately needed.

{{block}} directives in email templates are checked against a restricted-class policy. Templates that instantiate a block class the policy rejects will render that directive as empty. Standard blocks and the frontend area are unaffected. If you have custom transactional email templates that reference unusual block classes, preview them after upgrading. The policy is configurable through DI if you need to allow a specific class.

Resolved directive output is no longer re-parsed by later filter passes. If you rely on a custom filter that deliberately emits template syntax from one directive for a later pass to evaluate, that indirection no longer happens. Explicitly deferred directives are signed and still pass through. This can be disabled through DI.

Template include paths are validated against the application root. Custom template engines or deployment layouts that render templates from outside the application root — for example a symlinked shared-template directory resolving outside the project — will need those paths brought inside the root.


Contributors

Thanks to everyone who contributed to this release:

Ryan Hoerr, Tu Van, emetik, Lucas van Staden and Marcel Martinez — Michiel Gerritsen for reviewing the hardening work under time pressure, and Damien Retzinger, Daniel Sloof, Rick Bouma (rbouma) and Tihomir Vranješ for their help with the analysis.

For module-automatic-translation: Bashev, Girg-Z and Samuele Martini.

Upstream credit to Adobe for the security patches this release ports, and to Sansec for discovering StyleSmuggler and reporting it.